最长公共子序列LCS

模板:

#include<iostream>
#include<cstdio>
#define maxn 10010
using namespace std;
template<typename T>
inline void read(T &x){
    x=0; bool flag=0; char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c=='-') flag=1;
    for(;isdigit(c);c=getchar()) x=x*10+(c^48);
    if(flag) x=-x;
}

int n;
int a[maxn],b[maxn],f[maxn][maxn];

int main(){
    read(n);
    for(int i=1;i<=n;i++) read(a[i]);
    for(int i=1;i<=n;i++) read(b[i]);
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            f[i][j]=max(f[i-1][j],f[i][j-1]);
            if(a[i]==b[j]) f[i][j]=f[i-1][j-1]+1;
        }
    }
    printf("%d
",f[n][n]);
    return 0;
}

可惜暴力算法时间复杂度O(n2)被P1439【模板】最长公共子序列卡了50分

P1439【模板】最长公共子序列

所以正解是把LCS转换成求a的LIS得到时间复杂度O(nlogn)

注意这种做法要保证给出的是两个排列(每个数字只出现一次),否则映射的时候要每个数字映射多次,解决方法是把它倒过来映射,保证每个数字只取一次不会重复,好吧在确定每个数字能出现多少次(比如10次)的时候也能做,时间复杂度O(m*nlogn),m为每个数字出现次数(比如O(10*nlogn))

但是!对于普通的LCS来说,可能会有每个数字出现n次的极端情况!这样的复杂度就退化到了O(n2logn)!自己造数据的时候要注意!

贴一下AC代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#define maxn 100010
using namespace std;
template<typename T>
inline void read(T &x){
    x=0; bool flag=0; char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c=='-') flag=1;
    for(;isdigit(c);c=getchar()) x=x*10+(c^48);
    if(flag) x=-x;
}

int n,a[maxn],b[maxn];
int cnt,rank[maxn],qianzhuihe[maxn];//rank存映射后的新队列,qianzhuihe存维护的LIS前缀 

signed int main(){
    read(n);
    for(int i=1;i<=n;i++) read(a[i]);
    for(int i=1;i<=n;i++) {
        read(b[i]);
        rank[b[i]]=i;//映射 
    }
    for(int i=1;i<=n;i++) a[i]=rank[a[i]];
    for(int i=1;i<=n;i++){
        if((cnt==0)||(a[i]>qianzhuihe[cnt-1])) qianzhuihe[cnt++]=a[i];//维护的前缀为空或满足递增条件时,把a[i]加到数组里 
        else { 
            int s=lower_bound(qianzhuihe,qianzhuihe+cnt,a[i])-qianzhuihe;//找到前缀和(qianzhuihe)里第一个>a[i]的元素 ,注意s为下标 
            qianzhuihe[s]=a[i];//用a[i]替换掉这个元素 
//            * lower_bound(qianzhuihe,qianzhuihe+cnt,a[i])=a[i];//另一种写法,与上面两行等价 
//            注意,上升为>=a[i]第一个元素 用lower_bound,不降为>a[i]第一个元素 用upper_bound 
        }
    }
    printf("%d
",cnt);
    return 0;
}

注意第26行是 qianzhuihe[cnt++] 而不是 qianzhuihe[++cnt]并在输出时cnt-1 ,否则得分100->30

原文地址:https://www.cnblogs.com/DReamLion/p/14370448.html