本题相当于按照第一个人的序列为每个出现的数重新标号,按这些标号转换第二个序列,再对第二个序列求最长上升子序列。
求最长上升子序列需要O(nlogn)的方法。用d[i]表示到i位置最长序列长度,那么如果两个序列长度一样,结尾数大的那个序列一定可以被另一个小的代替。
用g[i]表示长度为i的序列中,结尾数最小的数。每次对于新的位置在g数组中二分出第一个大于它的数g[i] ,那么g[i-1]的数比它小,所以以它为结尾的最长序列长度就是i,用它替换掉之前g[i]中的数。
注意lower_bound数组必须是有序的!g数组开始要初始化为最大值。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int n,p,q;
int Hash[63000];
int a[63000];
int b[63000];
int g[63000];
int main(){
int T;
int kase=1;
scanf("%d",&T);
while(T--){
memset(Hash,0,sizeof(Hash));
scanf("%d%d%d",&n,&p,&q);
for(int i=1;i<=p+1;i++){
scanf("%d",&a[i]);
Hash[a[i]]=i;
}
for(int i=1;i<=q+1;i++){
scanf("%d",&b[i]);
}
memset(g,0x3f,sizeof(g));
g[1]=Hash[b[1]];
int res=0;
int k=1;
for(int i=2;i<=q+1;i++){
if(!Hash[b[i]]) continue;
int k=lower_bound(g+1,g+i,Hash[b[i]])-g;
g[k]=Hash[b[i]];
res=max(res,k);
}
printf("Case %d: %d\n",kase++,res);
}
return 0;
}

被折叠的 条评论
为什么被折叠?



