1. 程式人生 > >洛谷 P1439 【模板】最長公共子序列

洛谷 P1439 【模板】最長公共子序列

clu () 休閑 一句話 中一 AD DC == c++

神TM模板。。我本來想休閑一下寫點水題的。。。

開始做的時候直接敲了一個O(N2)的算法上去,編譯的時候才發現根本開不下。。

好了,談回這道題。

先不加證明的給出一種算法。

若有一組數據
2
4 2 5 1 3
2 5 4 1 3
那麽我們令
4 2 5 1 3
| | | | |
1 2 3 4 5
第三行的數據就變成
2 3 1 4 5
很明顯,答案是這個數據的最長上升子序列,即4 == 2 3 4 5,即原數列的2 5 1 3。

現在來大概的介紹一下這樣做的原因。

首先,觀察題目,註意到這個題和真正的模板的區別:給出1-n的兩個排列P1和P2。

思考排列的性質,及從1-N的每個數會且僅會出現一次。

引用洛谷題解中一句話,因為最長公共子序列是按位向後比對的,所以a序列每個元素在b序列中的位置如果遞增,就說明b中的這個數在a中的這個數整體位置偏後,可以考慮納入LCS——那麽就可以轉變成nlogn求用來記錄新的位置的map數組中的LIS

於是即可寫出代碼。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 const int MAXN = 1e5 + 20;
 4 const int INF = 0x3f3f3f3f;
 5 
 6 inline int read()
 7 {
 8     int x = 0; char
ch = getchar(); 9 while(!isdigit(ch)) ch = getchar(); 10 while(isdigit(ch)) x = x * 10 + ch - 0, ch = getchar(); 11 return x; 12 } 13 14 int N; 15 int a[MAXN], f[MAXN]; 16 17 int main() 18 { 19 cin>>N; 20 for(int i = 1; i <= N; i++) 21 a[read()] = i; 22 23 memset(f, 0x3f
, sizeof(f)); 24 int cur; 25 for(int i = 1; i <= N; i++) 26 { 27 cur = a[read()]; 28 *lower_bound(f, f + N + 1, cur) = cur; 29 } 30 31 cout<<(lower_bound(f, f + N + 1, INF) - f)<<endl; 32 return 0; 33 }

洛谷 P1439 【模板】最長公共子序列