1. 程式人生 > >最長公共子序列-LCS問題 (LCS與LIS在特殊條件下的轉換) [洛谷1439]

最長公共子序列-LCS問題 (LCS與LIS在特殊條件下的轉換) [洛谷1439]

一個 har define 分享 amp lis read ios stack

題目描述

給出1-n的兩個排列P1和P2,求它們的最長公共子序列。

輸入

第一行是一個數n,

接下來兩行,每行為n個數,為自然數1-n的一個排列。

輸出

一個數,即最長公共子序列的長度

輸入樣例
5 
3 2 1 4 5
1 2 3 4 5
輸出樣例
3

說明

對於50%的數據,n≤1000

對於100%的數據,n≤100000

思路

常見的LCS問題是通過O(n2)的DP解決的,顯然此題的數據是過不去的

如何想辦法?

這裏就要參考在特殊條件下LCS與LIS(最長上升序列)的轉換

我們記錄下第一個排列每一個數字出現的位置,即Hash[ ai ] = i

而這個序列再按第二個排列排序,即新型成的序列Seq[ i ] = Hash[ bi ]

這樣做了以後發現有什麽規律呢?

新的序列Seq是滿足B排列的先後順序單調遞增的,而在Seq的Hash值是按A排列的先後順序單調遞增的

那麽在Seq中找到的最長上升序列就是同時滿足A序列和B序列的先後關系的一個子序列

這樣就把LCS成功的轉換成了LIS問題

我們知道LIS的問題是可以O(n log n) 的解決的,在此不作贅述。

那麽我們前面提到的特殊條件是什麽呢?

由於這裏記錄的是Hash值,所以不能有重復的數字。

代碼

技術分享
 1 #include<set>
 2 #include<map>
 3
#include<stack> 4 #include<queue> 5 #include<cstdio> 6 #include<cstring> 7 #include<iostream> 8 #include<algorithm> 9 #define RG register int 10 #define rep(i,a,b) for(RG i=a;i<=b;i++) 11 #define per(i,a,b) for(RG i=a;i>=b;i--) 12 #define
ll long long 13 #define inf (1<<30) 14 #define maxn 100005 15 using namespace std; 16 int n,cnt; 17 int hash[maxn],seq[maxn],dp[maxn]; 18 inline int read() 19 { 20 int x=0,f=1;char c=getchar(); 21 while(c<0||c>9){if(c==-)f=-1;c=getchar();} 22 while(c>=0&&c<=9){x=x*10+c-0;c=getchar();} 23 return x*f; 24 } 25 26 void solve() 27 { 28 int l,r,mx=0,mid,p; 29 rep(i,1,n) 30 { 31 l=1,r=mx,p=0; 32 while(l<=r) 33 { 34 mid=(l+r)>>1; 35 if(dp[mid]<=seq[i]) p=mid,l=mid+1; 36 else r=mid-1; 37 } 38 if(p==mx) dp[++mx]=seq[i]; 39 else dp[p+1]=min(dp[p+1],seq[i]); 40 } 41 cout<<mx; 42 } 43 44 int main() 45 { 46 int tmp; 47 n=read(); 48 rep(i,1,n) tmp=read(),hash[tmp]=i; 49 rep(i,1,n) tmp=read(),seq[++cnt]=hash[tmp];//如果兩個序列的值有不相同的,請在逗號處加上 if(hash[tmp]),此題因為是排列所以不用加 50 solve(); 51 return 0; 52 }
View Code

最長公共子序列-LCS問題 (LCS與LIS在特殊條件下的轉換) [洛谷1439]