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

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

inf bubuko return https == span ++ 每一個 upper

題目傳送門

看起來是一道十分經典的LCS問題

很容易想到 n2 的一般算法:
主題代碼如下:

for (int i = 1; i <= n; i++)
      for (int j = 1; j <= n; j++){
      	dp[i][j] = max (dp[i-1][j], dp[i][j-1]);
      	if (a[i] == b[j]) dp[i][j] = max (dp[i][j], dp[i-1][j-1] + 1);
	  }
  printf ("%d", dp[n][n]); 

但往下看一眼數據範圍 :

技術分享圖片

沒錯, n ≤100000n²直接

TLE

題目描述中提到了兩組數都是 自然數1-n的一個排列

所以這題可以這麽來做:

設兩個數組分別為 a 和 b

對於每一個a數組中的數,一定有一個唯一對應的相等的b數組中的數

可以將a數組中的數看作 1,2,3,4,5......n

將b數組中的數也變為對應的值,假設變為數組c,可以發現,這變成了一個最長上升子序列LIS問題

當c中的數有一個上升子序列時,則這個序列在原數組中一定與a數組是公共的

模擬一遍樣例:
技術分享圖片

先把第一列數看作 1, 2, 3, 4, 5。 則3對應1, 2對應2, 1對應3 .......

第二列數變為 3, 2, 1, 4, 5

最長上升子序列為 1, 4, 5 或 2, 4, 5或3, 4, 5

可以發現,這三個序列在原數組中都能找到相應的公共部分

所以答案為3

完整代碼:

#include <bits/stdc++.h>
using namespace std;
#define f(i, r)  for (int i = 1; i <= r; i++)
int n, x, a[100005], k[100005], len, q[100005];
int main(){
	scanf ("%d", &n);
	f (i, n) scanf ("%d", &x), k[x] = i;
    f (i, n) scanf ("%d", &a[i]), a[i] = k[a[i]];
	f (i, n){
		if (a[i] > q[len]) q[++len] = a[i];
		else{
			int w = upper_bound (q + 1, q + len + 1, a[i]) - q;
			q[w] = a[i];
		}
	} 
	printf ("%d", len);
	return 0;
}

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