又是训练指南上的一道经典题~~
http://uva.onlinejudge.org/external/106/10635.html
题意:有两个长度分别为p+1和q+1的序列,每个序列各个元素互不相同,且都是1~n^2的整数。求俩序列的LCS。
分析:LCS的O(pq)复杂度显然太慢。注意到“每个序列各个元素互不相同,且都是1~n^2的整数”,所以有个巧妙的转换,把A中的元素重新
按1~p+1编号,同时B也相同的映射编号,由于A为递增序列,所以LCS就是B中最长递增子序列,即LIS.这样就转换成求B的LIS问题,可以
在O(nlogn)的时间内解决。
LIS:
设dp[i]为以A[i]结尾的最长上升子序列的长度。
O(n^2)解法:dp[i] = max{0,dp[j] | j < i , Aj < Ai} + 1;
O(nlogn)解法:假设已经两个状态a和b满足Aa<Ab且dp[a]=dp[b];那么后续所有状态i选择a并不会比b差。这样,对于相同的dp值,就只需保留A最小的一个(详见代码)。
1 /* 2 Author:Zhaofa Fang 3 Lang:C++ 4 */ 5 #include <cstdio> 6 #include <cstdlib> 7 #include <sstream> 8 #include <iostream> 9 #include <cmath> 10 #include <cstring> 11 #include <algorithm> 12 #include <string> 13 #include <utility> 14 #include <vector> 15 #include <queue> 16 #include <stack> 17 #include <map> 18 #include <set> 19 using namespace std; 20 21 typedef long long ll; 22 #define DEBUG(x) cout<< #x << ':' << x << endl 23 #define REP(i,n) for(int i=0;i < (n);i++) 24 #define FOR(i,s,t) for(int i = (s);i <= (t);i++) 25 #define PII pair<int,int> 26 #define PB push_back 27 #define MP make_pair 28 #define FI first 29 #define SE second 30 #define lowbit(x) (x&(-x)) 31 #define INF (1<<30) 32 33 const int maxn = 250*250+10; 34 int A[maxn],B[maxn],pos[maxn],dp[maxn]; 35 36 int LIS(int n) 37 { 38 for(int i=1;i<=n;i++)A[i] = INF,dp[i] = 0; 39 for(int i=0;i<n;i++) 40 { 41 int k = lower_bound(A+1,A+1+n,B[i]) - A; 42 A[k] = B[i]; 43 dp[i] = k; 44 } 45 int mx = -1; 46 REP(i,n)mx = max(dp[i],mx); 47 return mx; 48 } 49 int main() 50 { 51 //freopen("in","r",stdin); 52 int T; 53 scanf("%d",&T); 54 REP(cas,T) 55 { 56 printf("Case %d: ",cas+1); 57 int n,p,q; 58 scanf("%d%d%d",&n,&p,&q); 59 memset(pos,0,sizeof(pos)); 60 REP(i,p+1) 61 { 62 scanf("%d",&A[i]); 63 pos[A[i]] = i+1; 64 } 65 REP(i,q+1) 66 { 67 scanf("%d",&B[i]); 68 B[i] = pos[B[i]]; 69 } 70 printf("%d\n",LIS(q+1)); 71 } 72 return 0; 73 }