大体题意:
给你两个数组,求最大公共子序列的长度?
思路:
数据很大,直接求最大公共子序列会超时!
需要转换 一下,因为题目中说 不会出现重复数字,所以可以给第一个数组 重新编号,那么可以映射到第二个数组,第二个数组没有在第一个数组中出现的就不要了,因为肯定不在公共子序列中!
转换完成之后,公共子序列肯定是第一个数组的子序列,并且第一个数组是严格递增的!因此公共子序列也是严格递增的!
因此问题就转换成了求第二个数组的最长上升子序列!
二分法 nlog n!
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 250*250 + 10;
int a[maxn],b[maxn];
int num[maxn];
int LIS[maxn];
int main(){
int T,kase = 0;
scanf("%d",&T);
while(T--){
int n,p,q;
scanf("%d %d %d",&n, &p, &q);
for (int i=0; i <= n*n; ++i)num[i] = -1;
for (int i = 1; i <= p+1; ++i)scanf("%d",&a[i]);
for (int i = 1; i <= q+1; ++i)scanf("%d",&b[i]);
int cnt = 0;
for (int i = 1; i <= p+1; ++i){
num[a[i]] = ++cnt;
}
cnt = 0;
for (int i = 1; i <= q+1; ++i){
if (num[b[i]] == -1)continue;
a[++cnt] = num[b[i]];
}
// for (int i = 1; i <= cnt; ++i)printf("%d ",a[i]);
// puts("");
int cur = 1;
LIS[cur] = a[1];
for (int i = 2; i <= cnt; ++i){
if (a[i] > LIS[cur]){
LIS[++cur] = a[i];
}else{
int pos = lower_bound(LIS,LIS+cur,a[i]) - LIS;
LIS[pos] = a[i];
}
}
printf("Case %d: %d\n",++kase,cur);
}
return 0;
}