lightoj 1421 - Wavio Sequence LIS变形

题目求一个长度为奇数的序列,然后这个序列里面前半部分升序后半部分降序,中间那个值是最大的,求最大长度。

首先序列可以拆分成一个升序,一个降序序列,然后因为中间值在两个序列中都有,所以就是中间点是可以O(n)枚举的,我们要求的就是以i为中点的情况下长度最长,也就是以i为终点的最长上升子序列和以i 为起点的最长下降子序列,因为要求两端序列长度相等,所以答案就是其中的最小值*2-1。

LIS有nlogn求法,应付10W刚好

#include
using namespace std;
#define N 101000
int num1[N],num2[N];
int ans[N],q[N],h[N];
int erfen(int s[],int l,int r,int x)
{
    int mid,ans=-1;
    while(l<=r)
    {
        mid=(l+r)/2;
        if(s[mid]>=x)
        {
            r=mid-1;
            ans=mid;
        }
        else
        {
            l=mid+1;
        }
    }
    return ans;
}
int main()
{
    int t;
    scanf("%d",&t);
    for(int cas=1;cas<=t;cas++)
    {
        int n,len;
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&num1[i]);
            num2[n-i+1]=num1[i];
        }
        memset(ans,0,sizeof(ans));
        memset(q,0,sizeof(q));
        ans[1]=num1[1];
        len=1;
        q[1]=1;
        for(int i=2;i<=n;i++)
        {
            if(num1[i]>ans[len])
            {
                ans[++len]=num1[i];
                q[i]=len;
            }
            else
            {
                int pos=erfen(ans,1,len,num1[i]);
                ans[pos]=num1[i];
                q[i]=pos;
            }
        }
        memset(h,0,sizeof(h));
        memset(ans,0,sizeof(ans));
        ans[1]=num2[1];
        len=1;h[n]=1;
        for(int i=2;i<=n;i++)
        {
            if(num2[i]>ans[len])
            {
                ans[++len]=num2[i];
                h[n-i+1]=len;
            }
            else
            {
                int pos=erfen(ans,1,len,num2[i]);
                ans[pos]=num2[i];
                h[n-i+1]=pos;
            }
        }
        int answer=1;
        for(int i=1;i<=n;i++)
        {
            int tmp=min(q[i],h[i]);
            answer=max(answer,tmp*2-1);
        }
        printf("Case %d: %d\n",cas,answer);
    }
    return 0;
}


你可能感兴趣的:(动态规划,dp,lightoj)