/*
题意:T组测试,输入n,p,q ,接下来两行,
第一行 p +1 个数,第二行 q + 1个数,这些数都在 N*N范围内 。
找出最长公共子序列。
因为 p,q范围较大,如果用 p*q 的做法会超时,
看了题解后知道了可以转成 LIS 来求,LIS 只要 NlonN 就可以辣。
*/
LCS转LIS,这里摘抄一段,
原文出自 “karsbin@stephy” 博客, http://karsbin.blog.51cto.com/1156716/966387
举例说明:
A:abdba
B:dbaaba
则1:先顺序扫描A串,取其在B串的所有位置:
2:a(2,3,5) b(1,4) d(0)。
3:用每个字母的反序列替换,则最终的最长严格递增子序列的长度即为解。
替换结果:532 41 0 41 532
最大长度为3.
简单说明:上面的序列和最长公共子串是等价的。
对于一个满足最长严格递增子序列的序列,该序列必对应一个匹配的子串。
反序是为了在递增子串中,每个字母对应的序列最多只有一个被选出。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #define MAX 250 5 using namespace std; 6 int sq[MAX*MAX+5],num[MAX*MAX+5],h[MAX*MAX+5]; 7 int Find(int c[],int len,int x) 8 { 9 int l=0,r=len,mid=(l+r)/2; 10 while(l<=r) 11 { 12 if(x<c[mid]) r -= 1; 13 else if(x>c[mid]) l += 1; 14 else return mid; 15 mid = (l+r)/2; 16 } 17 return l; 18 } 19 int main() 20 { 21 int cnt=0,t,n,p,q,y; 22 scanf("%d",&t); 23 while(t--) 24 { 25 int c=0; 26 scanf("%d%d%d",&n,&p,&q); 27 memset(num,0,sizeof(num)); 28 for(int i=1;i<=p+1;i++) 29 { 30 scanf("%d",&y); 31 num[y]=i; 32 } 33 for(int i=0;i<q+1;i++) 34 { 35 scanf("%d",&y); 36 if(num[y]) 37 sq[c++]=num[y]; 38 } 39 int len=1; 40 h[0] = -999999999; 41 h[1] = sq[0]; 42 for(int i=1;i<c;i++) 43 { 44 int x = Find(h,len,sq[i]); 45 h[x] = sq[i]; 46 if(x>len) len = x; 47 } 48 printf("Case %d: %d ",++cnt,len); 49 } 50 return 0; 51 }