P1439 【模板】最长公共子序列
题目描述
给出1-n的两个排列P1和P2,求它们的最长公共子序列。
输入输出格式
输入格式:
第一行是一个数n,
接下来两行,每行为n个数,为自然数1-n的一个排列。
输出格式:
一个数,即最长公共子序列的长度
输入输出样例
说明
【数据规模】
对于50%的数据,n≤1000
对于100%的数据,n≤100000
/* 关于LCS长度等于构造出来的新序列的LIS长度的证明: (1) A、B的一个公共子序列对应新序列的一个严格递增子序列 证: 假设A、B的某一个公共子序列长度为k,则其公共子序列在A和B中可以写为 {A1,A2, ..., Ak} {B1,B2, ..., Bk} 如此有A1 = B1,A2 = B2, ...., Ak = Bk, 考虑元素Bi在B中的序号P(Bi),则有 P(B1)< P(B2) < ... < P(Bk) 注意此严格递增子序列属于新序列的一个子序列,因此得证 (2) 新序列的一个严格递增子序列对应A、B的一个公共子序列 证: 设新序列的一个严格递增子序列{P1,P2, ..., Pk}, 任意两个相邻的P不可能属于A中同一个元素,因为A中某元素在B中的序号按照降序排列,且P为上升序列。 所以每个P均对应于A中不同位置的元素,设为{A1, A2, ..., Ak}。 且每个P也对应B中唯一的一个元素,假设为{B1,B2, ..., Bk}, 由P的定义可知A1= B1, A2 = B2, ...., Ak = Bk,因此得证。 步骤: (1) 计算A中每个元素在B中的序号,并构成新序列 (2) 使用LIS的方法计算最长严格递增子序列 (3) 获取最长公共子序列 */ #include<iostream> #include<cstdio> #include<algorithm> #include<vector> using namespace std; const int N=100005; int n; int a[N],b; int seq[N],seq_len; int lis[N],lis_len; vector<int> vec[N]; int read() { char c=getchar();int num=0; for(;!isdigit(c);c=getchar()); for(;isdigit(c);c=getchar()) num=num*10+c-'0'; return num; } int main() { n=read(); for(int i=1;i<=n;++i) a[i]=read(); for(int i=1;i<=n;++i) { vec[b=read()].push_back(i); } for(int i=1;i<=n;++i) for(int j=vec[a[i]].size()-1;j>=0;--j) seq[++seq_len]=vec[a[i]][j]; lis[++lis_len]=seq[1]; for(int i=2;i<=seq_len;++i) { if(seq[i]>lis[lis_len]) lis[++lis_len]=seq[i]; else lis[lower_bound(lis+1,lis+lis_len+1,seq[i])-lis]=seq[i]; } printf("%d",lis_len); return 0; }