题意:给定两个序列一个长度为p+1,一个为q+1,求两序列的LCS,序列中每个数字不重复,最大值为n*n,n不大于250。
思路:每个数都不重复,所以可以将源数据和下标置换,对数列做一个哈希变换,另一个数列也做相同的变换就可以的到一个新的数列。可以转换为求新序列的LIS。时间复杂度就会降到O(nlogn)。原因可以这样思考,由于b中的数字是通过a的变换得到的,所以b的所有子集都是a的一个子集,但是顺序不确定。考虑b的LIS,它一定是a的一个子集,这个子集是a中从左到右的(b中的递增序列),所以一定是b和a的公共序列,由于LIS最长,所以是LCS。
#include <stdio.h>
#include <algorithm>
#include <math.h>
#include <string>
#include <cstring>
#include <map>
#include <vector>
#include <iostream>
#include <string.h>
using namespace std;
typedef long long ll;
const int maxn = 300*300;
int dp[maxn];
int a[maxn],b[maxn];
int n,p,q;
int lis()
{
memset(dp,0,sizeof(dp));
int len=1;
dp[0]=b[0];
for(int i=1;i<q+1;i++){
int pos=lower_bound(dp,dp+len,b[i])-dp;
dp[pos]=b[i];
len=max(len,pos+1);
}
return len;
}
int main()
{
int t,kase=1;
scanf("%d",&t);
while(t--){
scanf("%d%d%d",&n,&p,&q);
for(int i=0;i<p+1;i++){
int tmp;
scanf("%d",&tmp);
a[tmp]=i+1;
}
for(int i=0;i<q+1;i++){
int tmp;
scanf("%d",&tmp);
b[i]=a[tmp];
}
int ans=lis();
printf("Case %d: %d\n",kase++,ans);
/*for(int i=0;i<q+1;i++)
printf("%d ",b[i]);
printf("\n");*/
}
return 0;
}