zoukankan      html  css  js  c++  java
  • 最长公共子序列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

  • 相关阅读:
    人物-作家-马克·吐温:马克·吐温
    人物-发明家-特斯拉:尼古拉·特斯拉
    视觉暂留-Info:这些神奇的“视觉暂留”动画,每一幅都让人拍案叫绝!
    视觉暂留:余晖效应/视觉暂留
    mingetty
    mesg
    md5sum
    man.conf
    man
    makemap
  • 原文地址:https://www.cnblogs.com/DReamLion/p/14370448.html
Copyright © 2011-2022 走看看