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

  • 相关阅读:
    NConsoler 介绍
    HOWTO:批量删除存储过程和表
    HOWTO:使ASP.NET网站Forms验证可以指定多个登录页面
    [架构模式实践]如何不让第三方服务/组件的故障阻碍开发和测试进度
    GDI+学习笔记
    脚印: SD2C 2009 参会小记(非技术篇)
    Expression Web使用问题,相关资源及今日阅读
    HOWTO:FirePHP乱码问题解决
    [ECSHOP挖寶]用戶注銷過程
    励志好文
  • 原文地址:https://www.cnblogs.com/DReamLion/p/14370448.html
Copyright © 2011-2022 走看看