uva10635 LCS映射转LIS

题目给定

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 }
View Code

 这道题目能够这样子转化是因为串中的数字是各不相同的,所以每个数字的映射是唯一的, 所以才能导致第一个串映射过后是递增的。

hdu的魔板也是用了映射,从而变成预处理,然后读入数据,能马上输出答案。