给你两个长度为 \(n\) 的排列 \(P_1\) 和 \(P_2\),这两个排列只包含 \([1,n]\) 范围内的整数各一个,求这两个排列的LCS(即:最长公共子序列)的长度。
输入的第一行包含一个整数 \(n(1 \le n \le 10^5)\),用于表示排列的长度。
输入的第二行包含 \(n\) 个整数,两两之间以一个空格分隔,用于表示排列 \(P_1\)。
输入的第三行包含 \(n\) 个整数,两两之间以一个空格分隔,用于表示排列 \(P_2\)。
输出一个整数,用于表示 \(P_1\) 和 \(P_2\) 的 LCS 长度。
5
1 2 3 4 5
2 5 3 1 4
3
样例说明:
样例中,\(P_1\) 和 \(P_2\) 的 LCS 为 \([2, 3, 4]\)。
暴力解法时间复杂度 \(O(n^2)\),空间可以优化到 \(O(2n)\),但是仍然会超时,实现代码如下:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 100010;
int f[2][maxn], n, a[maxn], b[maxn];
int main() {
cin >> n;
for (int i = 1; i <= n; i ++) cin >> a[i];
for (int i = 1; i <= n; i ++) cin >> b[i];
for (int i = 1; i <= n; i ++) {
for (int j = 1; j <= n; j ++) {
if (a[i] == b[j]) f[i%2][j] = f[(i-1)%2][j-1] + 1;
else f[i%2][j] = max(f[(i-1)%2][j], f[i%2][j-1]);
}
}
cout << f[n%2][n] << endl;
return 0;
}
由于刚才的分析中,如果 \(P_1[i] \ne P_2[j]\),则 \(d[i,j]\) 不能转移到 \(d[i+1,j+1]\),因为目标函数不能增加。这样,我们应该只关心满足 \(P_1[i] = P_2[j]\) 的状态 \(d[i,j]\),也就是说,可以把状态转移方程写成:
显然对于任意的 \(i\),满足 \(P_1[i] = P_2[j]\) 的 \(j\) 有且仅有一个,令 \(pair(i)\) 为这个唯一的值,则一共只有 \(n\) 个需要考虑的状态,即 \(d[i, pair(i)]\),那么边界条件是 \(d[n, pair(n)] = 1\)。按照 \(i=n-1,n-2, \cdots, i\) 的顺序来计算,则只要把目前计算出来的所有状态 \(d[i‘, pair(i‘)]\)(它们自然满足 i‘ \gt i)用合理的方式组织起来,可以很快地从其中找到满足 \(pair(i‘) \gt pair(i)\) 的最大状态即可。
基于上述思路,使用线段树来存储 \(pair(i)\) 和对应的 \(d[i, pair(i)]\) 信息。
实现代码如下:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 100010;
int n, a[maxn], b[maxn], pos[maxn], ans; // pos[b[i]] = i,因为pair在C++中有特殊用法,所以这里用pos[i]来表示pair(i)
int f[maxn<<2];
void push_up(int rt) {
f[rt] = max(f[rt<<1], f[rt<<1|1]);
}
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
void update(int p, int v, int l, int r, int rt) {
if (l == r) f[rt] = v;
else {
int mid = (l + r)/2;
if (p <= mid) update(p, v, lson);
else update(p, v, rson);
push_up(rt);
}
}
int query(int L, int R, int l, int r, int rt) {
if (L <= l && r <= R) return f[rt];
int mid = (l + r) / 2, res = 0;
if (L <= mid) res = max(res, query(L, R, lson));
if (R > mid) res = max(res, query(L, R, rson));
return res;
}
int main() {
cin >> n;
for (int i = 1; i <= n; i ++) cin >> a[i];
for (int i = 1; i <= n; i ++) {
cin >> b[i];
pos[b[i]] = i;
}
for (int i = 1; i <= n; i ++) {
int j = pos[a[i]];
int tmp = 1;
if (i != 1 && j != 1) tmp = max(tmp, query(1, j-1, 1, n, 1)+1);
update(j, tmp, 1, n, 1);
ans = max(ans, tmp);
}
cout << ans << endl;
return 0;
}
原文:https://www.cnblogs.com/quanjun/p/13193561.html