zoukankan      html  css  js  c++  java
  • 最长公共子序列-LCS问题 (LCS与LIS在特殊条件下的转换) [洛谷1439]

    题目描述

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

    输入

    第一行是一个数n,

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

    输出

    一个数,即最长公共子序列的长度

    输入样例
    5 
    3 2 1 4 5
    1 2 3 4 5
    
    输出样例
    3

    说明

    对于50%的数据,n≤1000

    对于100%的数据,n≤100000

    思路

    常见的LCS问题是通过O(n2)的DP解决的,显然此题的数据是过不去的

    如何想办法?

    这里就要参考在特殊条件下LCS与LIS(最长上升序列)的转换

    我们记录下第一个排列每一个数字出现的位置,即Hash[ ai ] = i

    而这个序列再按第二个排列排序,即新型成的序列Seq[ i ] = Hash[ bi ]

    这样做了以后发现有什么规律呢?

    新的序列Seq是满足B排列的先后顺序单调递增的,而在Seq的Hash值是按A排列的先后顺序单调递增的

    那么在Seq中找到的最长上升序列就是同时满足A序列和B序列的先后关系的一个子序列

    这样就把LCS成功的转换成了LIS问题

    我们知道LIS的问题是可以O(n log n) 的解决的,在此不作赘述。

    那么我们前面提到的特殊条件是什么呢?

    由于这里记录的是Hash值,所以不能有重复的数字。

    代码

     1 #include<set>
     2 #include<map>
     3 #include<stack>
     4 #include<queue>
     5 #include<cstdio>
     6 #include<cstring>
     7 #include<iostream>
     8 #include<algorithm>
     9 #define RG register int
    10 #define rep(i,a,b)    for(RG i=a;i<=b;i++)
    11 #define per(i,a,b)    for(RG i=a;i>=b;i--)
    12 #define ll long long
    13 #define inf (1<<30)
    14 #define maxn 100005
    15 using namespace std;
    16 int n,cnt;
    17 int hash[maxn],seq[maxn],dp[maxn];
    18 inline int read()
    19 {
    20     int x=0,f=1;char c=getchar();
    21     while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    22     while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    23     return x*f;
    24 }
    25 
    26 void solve()
    27 {
    28     int l,r,mx=0,mid,p;
    29     rep(i,1,n)
    30     {
    31         l=1,r=mx,p=0;
    32         while(l<=r)
    33         {
    34             mid=(l+r)>>1;
    35             if(dp[mid]<=seq[i])    p=mid,l=mid+1;
    36             else r=mid-1;
    37         }
    38         if(p==mx)    dp[++mx]=seq[i];
    39         else dp[p+1]=min(dp[p+1],seq[i]);
    40     }
    41     cout<<mx;
    42 }
    43 
    44 int main()
    45 {
    46     int tmp;
    47     n=read();
    48     rep(i,1,n) tmp=read(),hash[tmp]=i;
    49     rep(i,1,n) tmp=read(),seq[++cnt]=hash[tmp];//如果两个序列的值有不相同的,请在逗号处加上 if(hash[tmp]),此题因为是排列所以不用加
    50     solve();
    51     return 0;
    52 }
    View Code
  • 相关阅读:
    Java多线程的两种实现方式
    Java实现验证码的产生和验证
    web前端对上传的文件进行类型大小判断的js自定义函数
    Java前端Rsa公钥加密,后端Rsa私钥解密(支持字符和中文)
    了解火爆的区块链和比特币
    Java中调用JavaScript方法
    Java读取文件的问题
    SpringBoot热部署简介
    Java使用Jetty实现嵌入式Web服务器及Servlet容器
    『安全工具』目录扫描 DirBuster AND 御剑
  • 原文地址:https://www.cnblogs.com/ibilllee/p/7737468.html
Copyright © 2011-2022 走看看