标签:
洛谷1439 排列LCS问题
本题地址: http://www.luogu.org/problem/show?pid=1439
题目描述
给出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
【思路】
LCS转LIS + 二分优化LIS
首先明确题目的特殊性:序列为1-n的一个排列即一个序列中不存在重复的元素。
如果LCS正常思路算时间为O(n^2)而且空间需要二维,显然不适用于本题。
这里将第一个序列a重新编号为1..n,并以这个编号规则重新定义第二个序列b,则问题转化为求第二个序列的LIS。
O(nlogn)求LIS的方法:二分查找。构造一个g数组,g[i]表示d值为i且最小的a值,每次转移求d[i]可以从g中二分查找满足小于a[i]的最大d值,算法在白书上有过探讨(P62)这里不再赘述。
数据很大,可以考虑优化读入。
【代码】
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 using namespace std; 5 6 const int maxn = 100000+10; 7 const int INF=1<<30; 8 int n; 9 int a[maxn],b[maxn],d[maxn]; 10 11 inline int read_int() { 12 char c; c=getchar(); 13 while(!isdigit(c)) c=getchar(); 14 15 int x=0; 16 while(isdigit(c)) { 17 x=x*10+c-‘0‘; 18 c=getchar(); 19 } 20 return x; 21 } 22 23 int main() { 24 n=read_int(); 25 int tmp[maxn]; 26 for(int i=1;i<=n;i++) a[i]=read_int() , tmp[a[i]]=i; 27 for(int i=1;i<=n;i++) b[i]=read_int() , b[i]=tmp[b[i]]; 28 29 int g[maxn],ans=0; 30 for(int i=1;i<=n;i++) g[i]=INF; 31 for(int i=1;i<=n;i++) { 32 int k=lower_bound(g+1,g+n+1,b[i])-g; 33 d[i]=k; 34 g[d[i]]=b[i]; 35 ans=max(ans,d[i]); //return max 36 } 37 cout<<ans<<"\n"; 38 return 0; 39 }
标签:
原文地址:http://www.cnblogs.com/lidaxin/p/4897055.html