题目的本意是求LCS,但由于每个序列的元素各不相同,所以将A序列重新编号{1,2,,,p+1},将B序列重新编号,分别为B中的元素在A中对应出现的位置(没有的话就是0)。
在样例中就是A = {1 7 5 4 8 3 9},B = {1 4 3 5 6 2 8 9}
重新编号以后:
A = {1 2 3 4 5 6 7}, B = {1 4 6 3 0 0 5 7}(里面的0在求LIS时可以忽略)
这样求A、B的LCS就转变为求B的LIS
求LIS用二分优化,时间复杂度为O(nlogn)
第一次做的用二分求LIS的题是HDU 1025
http://www.cnblogs.com/AOQNRMGYXLMV/p/3862139.html
在这里再复习一遍
1 //#define LOCAL 2 #include <iostream> 3 #include <cstdio> 4 #include <cstring> 5 #include <algorithm> 6 using namespace std; 7 8 const int maxn = 250 * 250; 9 int num[maxn], s[maxn], dp[maxn]; 10 11 int main(void) 12 { 13 #ifdef LOCAL 14 freopen("10635in.txt", "r", stdin); 15 #endif 16 17 int T, kase; 18 scanf("%d", &T); 19 for(kase = 1; kase <= T; ++kase) 20 { 21 int N, p, q, x; 22 scanf("%d%d%d", &N, &p, &q); 23 memset(num, 0, sizeof(num)); 24 for(int i = 1; i <= p+1; ++i) 25 { 26 scanf("%d", &x); 27 num[x] = i; 28 } 29 int n = 1; 30 for(int i = 1; i <= q+1; ++i) 31 { 32 scanf("%d", &x); 33 if(num[x]) 34 s[n++] = num[x]; 35 } 36 //求s[1]...s[n]的LIS 37 dp[1] = s[1]; 38 int len = 1; 39 for(int i = 2; i <= n; ++i) 40 { 41 int left = 1, right = len; 42 while(left <= right) 43 { 44 int mid = (left + right) / 2; 45 if(dp[mid] < s[i]) 46 left = mid + 1; 47 else 48 right = mid - 1; 49 } 50 dp[left] = s[i]; 51 if(left > len) 52 ++len; 53 } 54 55 printf("Case %d: %d ", kase, len); 56 } 57 return 0; 58 }
大白书里面用到了lower_bound函数
函数介绍
lower_bound()返回一个 iterator 它指向在[first,last)标记的有序序列中可以插入value,而不会破坏容器顺序的第一个位置,而这个位置标记了一个大于value 的值。
效果是一样的
1 //#define LOCAL 2 #include <iostream> 3 #include <cstdio> 4 #include <cstring> 5 #include <algorithm> 6 using namespace std; 7 8 const int INF = 1000000000; 9 const int maxn = 250 * 250; 10 int num[maxn], s[maxn], g[maxn], d[maxn]; 11 12 int main(void) 13 { 14 #ifdef LOCAL 15 freopen("10635in.txt", "r", stdin); 16 #endif 17 18 int T, kase; 19 scanf("%d", &T); 20 for(kase = 1; kase <= T; ++kase) 21 { 22 int N, p, q, x; 23 scanf("%d%d%d", &N, &p, &q); 24 memset(num, 0, sizeof(num)); 25 for(int i = 1; i <= p+1; ++i) 26 { 27 scanf("%d", &x); 28 num[x] = i; 29 } 30 int n = 0; 31 for(int i = 1; i <= q+1; ++i) 32 { 33 scanf("%d", &x); 34 if(num[x]) 35 s[n++] = num[x]; 36 } 37 //求s[1]...s[n]的LIS 38 for(int i = 1; i <= n; ++i) 39 g[i] = INF; 40 int ans = 0; 41 for(int i = 0; i < n; ++i) 42 { 43 int k = lower_bound(g+1, g+n+1, s[i]) - g; 44 d[i] = k; 45 g[k] = s[i]; 46 ans = max(ans, d[i]); 47 } 48 printf("Case %d: %d ", kase, ans); 49 } 50 return 0; 51 }