使用常规的LCS思路(也就是动态规划),时间复杂度,数据太大,肯定会TLE(如果数据不大,也不会是绿题了),再次读题,发现题目中多给了一个条件,序列是n的一个全排列,那么两个序列所包含的数字都是一样的,只是排列顺序不一样。
那么就有一个十分巧妙的处理方法,利用map,建立映射,以A序列(3 2 1 4 5)为基准,即3-a,2-b,1-c,4-d,5-e,那么A序列就变为(a b c d e),是一个上升序列,B序列就变为(c b a d e),A,B的公共最长子列长度肯定不变,而这时有了有趣的性质:A,B的公共子列必是A的子列,而A是上升的,因此问题就转化为求序列B的最长上升子列问题(LIS)问题。
3 2 1 4 5
a b c d e
c b a d e
1 2 3 4 5
但考虑到数据量太大的问题的复杂度并不好,不采用动态规划的方法,而是使用一个辅助数组
,来实时保存最长上升子列的长度,将B序列扫一遍,最终d数组的长度就是答案,复杂度为
,就能AC啦。
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
#define int long long
#define x(i) x+dirx[i]
#define y(i) y+diry[i]
int a[N],b[N],n,d[N];
map<int,int> s;
int LIS()
{
int len=0;
for(int i=1;i<=n;i++)
{
if(b[i]>d[len]) d[++len]=b[i];
else
{
int it=lower_bound(d,d+len,b[i])-d;
d[it]=b[i];
}
}
return len;
}
signed main()
{
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
s[a[i]]=i;
a[i]=i;
}
for(int i=1;i<=n;i++)
{
cin>>b[i];
b[i]=s[b[i]];
}
//转化为求序列b的最长上升子列问题
cout<<LIS()<<"\n";
return 0;
}