LIS问题的简短

导弹拦截
时间复杂度O(nlogn)
求最长上升子序列时:
dp[p] ,p代表最长不上升子序列的子序列的编号从1开始增加,根据dw定理,最大的m编号即是最长上升子序列的长度也是最少分成了m组非上升子序列。

#include<bits/stdc++.h>
using namespace std;
int a[100010],dp1[100010],dp2[100010],n;
int main(){
    while(cin>>a[++n]);
    --n;
    //最不上升子序列
    int m=0;
    for(int i=1;i<=n;++i){
        int p=upper_bound(dp1+1,dp1+1+m,a[i],greater<int>())-dp1;
        dp1[p]=a[i];
        m=max(m,p);
    }
    cout<<m<<endl;
    m=0;
    //最长上升子序列
    for(int i=1;i<=n;++i){
        int p=lower_bound(dp2+1,dp2+1+m,a[i])-dp2;
        dp2[p]=a[i];
        m=max(m,p);
    }
    cout<<m<<endl;
    return 0;
}


这种写法可以很好解决二维偏序需要记录分组的情况
E2. String Coloring (hard version)
给出一串小写字母,输出划分最少的子序列个数使得每个子序列没有逆序,并输出每个字母所属的子序列编号。

input:

7
abcdedc

output:

3
1 1 1 1 1 2 3

最长非降子序列分组对应求最长下降子序列个数

#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+10;
int dp[maxn];
char s[maxn];
int ans[maxn];
int main(){
    int n;
    scanf("%d",&n);
    scanf("%s",s+1);
    int m=0;
    for(int i=1;s[i];++i){
        int p=lower_bound(dp+1,dp+1+m,s[i]-'a'+1,greater<int>())-dp;
        dp[p]=s[i]-'a'+1;
        m=max(m,p);
        ans[i]=p;
    }
    cout<<m<<endl;
    for(int i=1;i<=n;++i){
        cout<<ans[i]<<" ";
    }
    return 0;
}

发布了96 篇原创文章 · 获赞 11 · 访问量 2254

猜你喜欢

转载自blog.csdn.net/weixin_43769146/article/details/104335568
lis