最长公共子序列 - 题目 - Daimayuan Online Judge
题意:
给出从 1到 n的两个排列 P1 和 P2,求它们的最长公共子序列。
这是道好题
一开始以为是模板题,但是看到数据范围就知道数组开不下,因此就知道这道题不简单了
思路:
和LCS模板不同之处在于,这道题给出的是两个排列,因此要根据排列的性质去做
排列常见的性质就是每个数在排列中仅出现一次
因此有关排列的题的常用操作就是记录每个元素的位置
两个序列的公共子序列的特点是一个序列中的那个子序列放到第二个序列中,这个子序列的字符的相对位置不变,即给定第一个子序列中的字符的下标,把它放到第二个子序列中,下标仍然是递增的
因此这道题中,我们只需记录第一个数组中的元素在第二个数组中的位置,然后把这些位置构成一个数组,对这个数组做一次最长上升子序列即可
最长上升子序列时间复杂度为O(nlogn),空间只需开一维数组即可
Code:
#include <bits/stdc++.h>
using namespace std;
const int mxn=1e5+10;
unordered_map<int,int> mp;
int n,len=0;
int a[mxn],b[mxn],c[mxn],f[mxn];
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]),mp[a[i]]=i;
for(int i=1;i<=n;i++) scanf("%d",&b[i]),c[i]=mp[b[i]];
f[++len]=c[1];
for(int i=2;i<=n;i++){
if(c[i]>f[len]) f[++len]=c[i];
else{
int pos=lower_bound(f+1,f+1+len,c[i])-f;
f[pos]=c[i];
}
}
printf("%d\n",len);
return 0;
}
总结:
1.排列常见的性质就是每个数在排列中仅出现一次
因此有关排列的题的常用操作就是记录每个元素的位置
2.两个序列的公共子序列的特点是一个序列中的那个子序列放到第二个序列中,这个子序列的字符的相对位置不变,即给定第一个子序列中的字符的下标,把它放到第二个子序列中,下标仍然是递增的