洛谷 P1439 排列LCS问题
原创
©著作权归作者所有:来自51CTO博客作者mb63eca9f086a52的原创作品,请联系作者获取转载授权,否则将追究法律责任
题目描述
给出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
【分析】
一个好的题解比那些冗长的题解不知道好到哪里去
借鉴洛谷题解
首先简化一下问题,假设P1恰好为单调递增的1,2,3,…n,那么很显然答案就是P2的最长上升子序列的长度(想一想,为什么?)
问题是P1并非单调递增的,但我们可以假定它就是1,2,3,…,n,将P1[1]映射到1,P1[2]映射到2,……然后再将P2作相同的变换即可,这样只要求P2的最长上升子序列了。
不会LIS(最长上升子序列)算法的请自行百度…
【代码】
//P1439 排列LCS问题
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
#define M(a) memset(a,0,sizeof a)
#define fo(i,j,k) for(i=j;i<=k;i++)
using namespace std;
const int mxn=100005;
int a[mxn],mp[mxn],d[mxn];
int n,len;
int main()
{
int i,j,x;
scanf("%d",&n);
fo(i,1,n)
{
scanf("%d",&x);
mp[x]=i;
}
fo(i,1,n)
{
scanf("%d",&x);
a[i]=mp[x];
}
d[len=1]=a[1];
fo(i,2,n)
{
if(a[i]<d[1]) d[1]=a[i];
else if(a[i]>d[len]) d[++len]=a[i];
else d[lower_bound(d+1,d+len+1,a[i])-d]=a[i];
}
printf("%d\n",len);
return 0;
}