P1439 【模板】最长公共子序列
题目描述
给出 1,2,…,�1,2,…,n 的两个排列 �1P1 和 �2P2 ,求它们的最长公共子序列。
输入格式
第一行是一个数 �n。
接下来两行,每行为 �n 个数,为自然数 1,2,…,�1,2,…,n 的一个排列。
输出格式
一个数,即最长公共子序列的长度。
输入输出样例
输入 #1复制
5
3 2 1 4 5
1 2 3 4 5
输出 #1复制
3
说明/提示
对于 50%50% 的数据, �≤103n≤103;
对于 100%100% 的数据, �≤105n≤105。
思路
这个题目搞了好久,终于看了题解稍微懂了一点
因为两个序列都是 1~n的全排列,那么两个序列元素互异且相同,也就是说只是位置不同罢了,那么我们通过一个 map数组将 A序列的数字在 B序列中的位置表示出来。因为最长公共子序列是按位向后比对的,所以a序列每个元素在b序列中的位置如果递增,就说明b中的这个数在a中的这个数整体位置偏后,可以考虑纳入 LCS——那么就可以转变成 nlogn求用来记录新的位置的map数组中的 LIS。
巧妙地将LCS(最长公共子序列)转换成了LIS(最长递增子序列)
#include<stdio.h>
#define N 100010
int n,len,a[N],b[N],c[N],map[N];
int min(int x,int y)
{
return (x<y)?x:y;
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
b[a[i]]=i;
}
for (int i=1;i<=n;i++)
{
scanf("%d",&c[i]);
map[i]=99999999;
}
map[0]=0;
for (int i=1;i<=n;i++)
{
if (b[c[i]]>map[len]) map[++len]=b[c[i]];
else
{
int l=0,r=len;
while (l<r)
{
int mid=(l+r)/2;
if (map[mid]>b[c[i]])
r=mid;
else
l=mid+1;
}
map[l]=min(b[c[i]],map[l]);
}
}
printf("%d\n",len);
return 0;
}