10635

/*
题意: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 }
原文地址:https://www.cnblogs.com/ember/p/4909508.html