hdu5532 最长不上升子序列+最长不下降子序列

题目大意:让你求出这个串是否是近似有序串,什么叫做近似有序串呢,就是,这个串去掉任意一个字符也能保持有序。

算法思路:模板题,只需要求出最大的有序子串,然后看这个串总的长度-1是否小于等于最大有序子串的长度,如果不满足,则说明这个串不是近似串。如何求最大有序子串呢,就比较一下最长不上升子序列的长度和最长不下降子序列的长度,取最长的即可。

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define MAXN 100050
#define INF 0x3f3f3f3f
int t,a[MAXN],ans[MAXN],d[MAXN],S[MAXN],n;

int BSearch(int x, int y, int v) //二分求上界(不上升)
{
    while(x <= y)
    {
        int mid = x+(y-x)/2;
        if(S[mid] >= v) x = mid+1;
        else y = mid-1;
    }
    return x;
}
int BSearch2(int x, int y, int v) //二分求上界(不下降)
{
    while(x <= y)
    {
        int mid = x+(y-x)/2;
        if(S[mid] <= v) x = mid+1;
        else y = mid-1;
    }
    return x;
}

int LIS()//最长不下降子序列
{
    memset(d,0,sizeof(d));
    for(int i = 1; i <=n; i++) S[i] = INF;
    int res = 0;
   for(int i = 1; i <= n; i++)
    {
        int x = 1, y = i;
        int pos = BSearch2(x, y, a[i]);
        d[i] = pos;
        S[d[i]] = min(S[d[i]], a[i]);
        res = max(res, d[i]);
    }
    return res;
}
int LFS()//最长不上升子序列
{
     for(int i = 1; i <=n; i++) S[i] = -INF; //注意初始值
    memset(d, 0, sizeof(d));
    int res = 0;
    for(int i = 1; i <= n; i++)
    {
        int x = 1, y = i;
        int pos = BSearch(x, y, a[i]);
        d[i] = pos;
        S[d[i]] = max(S[d[i]], a[i]);
       res = max(res, d[i]);
    }
    return res;
}
int main()
{

    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);

        for(int i=1; i<=n; i++)
        {
            scanf("%d",&a[i]);
        }

        int len1=LIS();//nlogn
        int len2=LFS();//nlogn

        int flag=max(len1,len2);

        if(n-1<=flag)
        {
            printf("YES\n");
        }
        else
        {
            printf("NO\n");
        }


    }



    return 0;

}

 这里顺便补充一下,最长上升子序列和最长下降子序列的模板,过几天就去比赛了,记录一下。

#include<cstdio>
#include<cstring>
#define MAXN 40005

int arr[MAXN],ans[MAXN],len;



int binary_search(int i)
{
    int left,right,mid;
    left=0,right=len;
    while(left<right)
    {
        mid = left+(right-left)/2;
        if(ans[mid]>=arr[i]) right=mid;
        else left=mid+1;
    }
    return left;
}

int main()
{
   
    int T,p,i,j,k;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&p);
        for(i=1; i<=p; ++i)
            scanf("%d",&arr[i]);

        ans[1] = arr[1];
        len=1;
        for(i=2; i<=p; ++i)
        {
            if(arr[i]<ans[len]) //这个是求最长上升子序列,如果是求下降的话,改成小于号即可
                ans[++len]=arr[i];
            else
            {
                int pos=binary_search(i);   
                ans[pos] = arr[i];
            }

        }
        printf("%d\n",len);
    }

    return 0;

}

猜你喜欢

转载自huyifan951124.iteye.com/blog/2330542