zoukankan      html  css  js  c++  java
  • 洛谷 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/
  • 相关阅读:
    Sum Root to Leaf Numbers
    Sum Root to Leaf Numbers
    Sort Colors
    Partition List
    Binary Tree Inorder Traversal
    Binary Tree Postorder Traversal
    Remove Duplicates from Sorted List II
    Remove Duplicates from Sorted List
    Search a 2D Matrix
    leetcode221
  • 原文地址:https://www.cnblogs.com/Menteur-Hxy/p/9248039.html
Copyright © 2011-2022 走看看