传送门
最长公共子序列可以考虑转化为最大上升子序列。很容易想到用结构体存储元素i(1<=i<=n)分别在两个序列中出现的位置,按其在第一个序列中出现的位置排序,对样例便有:
此时i在a中出现顺序一定从前往后排列,求最大公共子序列长度只需找到b中最长的上升子序列长度即可。
#include<bits/stdc++.h>
#define ff(i,s,e) for(int i=s;i<=e;i++)
using namespace std;
inline int read(){
register int x=0,f=1;register char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
const int m=100005;
int n,f[m];
struct qwq{
int a,b;
}x[m];
bool cmp(qwq x,qwq y){
return x.a<y.a;
}
int find(int l,int r,int x){//二分在已知上升序列中找第一个大于x的数
while(l<=r){
int mid=(l+r)/2;
if(f[mid]<x) l=mid+1;
else r=mid-1;
}
return l;
}
int main(){
n=read();
ff(i,1,n) x[read()].a=i;
ff(i,1,n) x[read()].b=i;
sort(x+1,x+n+1,cmp);
int len=0;
ff(i,1,n){
if(x[i].b>f[len])//若大于当前最大上升子序列最大元素,存储
f[++len]=x[i].b;
else{f[find(1,len,x[i].b)]=x[i].b;}//用x替换大于x的数,保证后面解最优
}
printf("%d",len);
return 0;
}
看下数据,n最大可以达到1e5,显然普通dp的O(n2)求法会爆,便能想到二分。