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


    LIS LCS 映射

    题目描述

    给出1-n的两个排列P1和P2,求它们的最长公共子序列。

    输入输出格式

    输入格式:
    第一行是一个数n,

    接下来两行,每行为n个数,为自然数1-n的一个排列。

    输出格式:
    一个数,即最长公共子序列的长度

    输入输出样例

    输入样例#1:
    5
    3 2 1 4 5
    1 2 3 4 5
    输出样例#1:
    3
    说明

    【数据规模】

    对于50%的数据,n≤1000

    对于100%的数据,n≤100000

    无法相信这是模板题QAQ
    看此题的数据范围,显然使用最长公共子序列的一般DP算法(时间复杂度为O(N^2))肯定会超时,所以我们需要想别的方法。

    考虑此题的另一个条件,两个序列都为1…n的一个排列,考虑特殊情况:

    如果其中一个排列为(1,2,…,n),另一个排列为(a1,a2,…,an),那么对于两者的任意公共子序列(a[b1],a[b2],…,a[bk]),必有a[b1] < a[b2] < …< a[bk],则两序列的最长公共子序列为排列(a1,a2,…,an)的最长上升子序列。

    那么,对于两个一般的排列(a1,a2,…,an)和(b1,b2,…,bn)的最长公共子序列怎么求?

    我们定义映射f(ai)=i,那么两个排列可以转换为(f(a1),f(a2),…,f(an))=(1,2,…,n)和(f(b1),f(b2),…,f(bn)),我们进行这样的转换之后,就把本题转换为求最长上升子序列的长度的题目了。
    之后便可以用LIS的nlogn算法计算了。
    总的时间复杂度为处理映射O(N),求LIS长度为O(N log N),总的时间复杂度为O(N log N)

    code:

    #include<cstdio>
    
    int n,top;
    int a[100005],dp[100005],f[100005];
    
    int search(int x){
        int l=1,r=top,mid;
        while(l<r){
            mid=(l+r)>>1;
            if(dp[mid]<x) l=mid+1;
            else r=mid; 
        }
        return l;
    }
    
    int main(){
        scanf("%d",&n);
        for(int i=1;i<=n;i++) {
            scanf("%d",&a[i]);
            f[a[i]]=i;
        } 
        for(int i=1;i<=n;i++) {
            scanf("%d",&a[i]);
            a[i]=f[a[i]];
        }
        for(int i=1;i<=n;i++){
            if(dp[top]<=a[i]) dp[++top]=a[i];
            else dp[search(a[i])]=a[i];
        }
        printf("%d",top);
        return 0;
    }
    版权声明:本文为博主原创文章,未经博主允许不得转载。 博主:https://www.cnblogs.com/Menteur-Hxy/
  • 相关阅读:
    Python基础(函数)
    Python基础(列表中变量与内存关系)
    linux文件、目录管理
    安装、登入centos7
    Python基础(if语句、运算符)
    Python基础(列表、元组)
    Python基础(变量、字符编码、数据类型)
    初识Python
    解决子级用css float浮动 而父级div没高度不能自适应高度
    PHP服务端优化全面总结
  • 原文地址:https://www.cnblogs.com/Menteur-Hxy/p/9248039.html
Copyright © 2020-2023  润新知