题目给定
2个序列,要我们求LCS,但是序列的长度最长是250*250, LCS的时间复杂度是O(N*N),所以无法解决
我们可以第一个序列的数字,按位置,映射为1、2、3、4、5、6、7、8、9
那么就会得到一个映射函数,将第二个序列,映射为一个新的序列
那么就相当于用一个映射函数将两个字符串映射为两个新的字符串
我们会发现,LCS的长度是不会改变的
因为两个序列中相同的字符映射之后仍然相同
所以只要求两个序列的LCS即可
然后我们发现,第一个序列是递增的,那么求出来的LCS肯定也是递增的
那么我们是不是只要求第二个序列的最长递增子序列就可以了呢
答案是:yes
而LIS有 O(nlogn)的算法
所以复杂度降低了,从而可以求解题目
1 #include <stdio.h> 2 #include <string.h> 3 #include <stdlib.h> 4 #include <algorithm> 5 #include <iostream> 6 #include <queue> 7 #include <stack> 8 #include <vector> 9 #include <map> 10 #include <set> 11 #include <string> 12 using namespace std; 13 typedef long long LL; 14 const int INF = 1<<30; 15 const int N = 90000; 16 int a[N],b[N]; 17 int reflect[N]; 18 int st[N],top; 19 int main() 20 { 21 int t,n,p,q,i,j,tCase; 22 scanf("%d",&tCase); 23 for(t=1; t<=tCase; ++t) 24 { 25 top = 0; 26 scanf("%d%d%d",&n,&p,&q); 27 p++; 28 q++; 29 for(i=1; i<=p; ++i) 30 { 31 scanf("%d",&a[i]); 32 reflect[a[i]] = i; 33 } 34 for(i=1; i<=q; ++i) 35 { 36 scanf("%d",&b[i]); 37 b[i] = reflect[b[i]]; 38 } 39 st[top] = b[1]; 40 for(i=2; i<=q; ++i) 41 { 42 if(b[i] > st[top]) 43 { 44 st[++top] = b[i]; 45 } 46 else 47 { 48 int low = 0, high = top; 49 while(low <= high) 50 { 51 int mid = (low + high) >> 1; 52 if(b[i] > st[mid]) 53 low = mid + 1; 54 else 55 high = mid - 1; 56 } 57 st[low] = b[i]; 58 } 59 } 60 printf("Case %d: %d ",t,top+1); 61 } 62 63 return 0; 64 }
这道题目能够这样子转化是因为串中的数字是各不相同的,所以每个数字的映射是唯一的, 所以才能导致第一个串映射过后是递增的。
hdu的魔板也是用了映射,从而变成预处理,然后读入数据,能马上输出答案。