挑战LIS (二分 加 正反遍历)

来源:互联网 发布:vue main.js引入less 编辑:程序博客网 时间:2024/05/17 00:14


对于一个数的序列a1,a2...an,当满足a1<a2<...<an时,我们定义这样的序列是严格递增(上升)的序列。我们还可以从这个序列中抽出部分数字(至少1个)
并按原有顺序排列,组成新的序列,我们称之为一个子序列。
最长上升子序列(Longest Increasing Subsequence,LIS)是一个非常经典的问题,它是指一个序列中最长且严格递增的子序列。
对于求一个已知序列的LIS的长度,我们有一个非常易懂的方法。
设原有序列a的长度为n,定义f[i]表示从a[1]至a[i],且以a[i]为结尾最长上升子序列的长度,
则f[i](1<=i<=n)可以由以下的C++代码计算
for (int i=1; i<=n; i++) {
    int maxValue=0;
    for (int j=1; j<=i-1; j++) {
        if (a[j]<a[i]&&f[j]>maxValue) {
            maxValue=f[j];
        }
    }
    f[i]=maxValue+1;

}

最终在f[i] (1<=i<=n)中取最大值,我们便可以得到LIS的长度。

现在,我们不止对最长上升子序列的长度感兴趣,并且想要知道对于原有序列中的每个数是否属于某个最长上升子序列。

输入格式

多组输入数据
每组数据第一行为一个数n,(1<=n<=999)表示原序列的长度

下一行为n个整数(在int范围内),分别是a1至an。


输出

每组数据分为两行输出,第一行为一个整数L,表示原序列的最长上升子序列的长度。

第二行为n个连续的数字,若原序列某个数字不属于任意最长上升子序列,则输出数字1;若属于某个最长上升子序列则输出数字2。


样例输入

3
1 2 3
4
3 4 2 5
5
111 16 -73 11 9

样例输出

3
222
3
2212
2
11222



#include<iostream>#include<stdio.h>#include<string.h>#include<algorithm>#include<map>#include<queue>#include<math.h>#include<stack>using namespace std;#define LL long long#define mp(a,b) make_pair((a),(b))#define clr(x,a) memset(x,a,sizeof(x))#define INF 0x3f3f3f3f#define lb(x) ((x)&(-x))#define rep(i,a,b) for(int i=a;i<=b;i++)const int N=1005,siz=1e9;const int MOD=1e9+7;int n;int gcd(int x,int y){    return y==0?x:gcd(y,x%y);}int a[1005];int f[1005],g[1005],dp[1005];int solve(int len,int x){    int l=1,r=len+1;    int ret;    while(l<=r){        int m=(l+r)>>1;        if(l==len+1) return len+1;        if(x>=dp[m]){            ret=m;            r=m-1;        }else{            l=m+1;        }    }    return ret;}int main(){    //freopen("aaa.txt","r",stdin);    //freopen("bbb.txt","w",stdout);    while(~scanf("%d",&n)){        for(int i=0;i<n;i++){          scanf("%d",&a[i]);        }        clr(f,0);        clr(g,0);        clr(dp,0);        f[0]=1;        int len=1;        dp[1]=a[0];        for(int i=1;i<n;i++){            f[i]=lower_bound(dp+1,dp+len+1,a[i])-dp;            dp[f[i]]=a[i];            if(f[i]>len) len=f[i];        }        int ans=len;        g[n-1]=1;        clr(dp,0);        dp[1]=a[n-1];        len=1;        for(int i=n-2;i>=0;i--){            g[i]=solve(len,a[i]);            if(g[i]>len) len=g[i];            dp[g[i]]=a[i];        }//       for(int i=0;i<n;i++) cout<<f[i];//        cout<<endl;//        for(int i=0;i<n;i++) cout<<g[i];//        cout<<endl;        cout<<len<<endl;        for(int i=0;i<n;i++){            if(g[i]+f[i]==ans+1) cout<<2;            else  cout<<1;        }        cout<<endl;    }    return 0;}

0 0
原创粉丝点击