洛谷 最长公共子序列
P1439 【模板】最长公共子序列
题目描述
给出 1 , 2 , … , n 1,2,\ldots,n 1,2,…,n 的两个排列 P 1 P_1 P1 和 P 2 P_2 P2 ,求它们的最长公共子序列。
输入格式
第一行是一个数 n n n。
接下来两行,每行为 n n n 个数,为自然数 1 , 2 , … , n 1,2,\ldots,n 1,2,…,n 的一个排列。
输出格式
一个数,即最长公共子序列的长度。
输入输出样例 #1
输入 #1
5
3 2 1 4 5
1 2 3 4 5
输出 #1
3
说明/提示
- 对于 50 % 50\% 50% 的数据, n ≤ 1 0 3 n \le 10^3 n≤103;
- 对于
100
%
100\%
100% 的数据,
n
≤
1
0
5
n \le 10^5
n≤105。
一般的求最长公共子序列如下
int dp[1001][1001], a[2001], b[2001], n, m;
void solve() {
cin >> n >> m;
for(int i = 1; i <= n; i++) cin >> a[i];
for(int j = 1; j <= m; j++) cin >> b[j];
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= m; 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);
}
}
cout << dp[n][m];
return;
}
但该题数据范围比较大,但该题两个数组为排列数组,可以优化到时间复杂度为nlogn
int a[100009], b[100009], p[100009], f[100009];
void solve() {
int n;
cin>>n;
for(int i = 1; i <= n; i++) {
cin >> a[i];
p[a[i]] = i;
}
for(int i = 1; i <= n; i++) {
cin >> b[i];
f[i] = INF;
}
int len = 0;
f[0] = 0;
for(int i = 1; i <= n; i++) {
int l = 0, r = len, mid;
if(p[b[i]] > f[len]) f[++len] = p[b[i]];
//类似最长上升子序列的优化
else {
while(l < r) {
mid = l + r >> 1;
if(f[mid] > p[b[i]]) r = mid;
else l = mid + 1;
}
f[l] = min(f[l], f[b[i]]);
}
}
cout << len;
return;
}