题意
给出1∼n 的两个排列P1 和 P2,求它们的最长公共子序列。
输入格式
第一行是一个数 n (1≤n≤10^5)。
接下来两行,每行为 n 个数,为自然数1∼n 的一个排列。
输出格式
一个数,即最长公共子序列的长度。
思路
一开始用朴素的LCS算法(O(n²))来写,发现数据范围到1e5会超时,然后向大佬学习一种新思路:
将LCS问题转换为求LIS问题,具体做法就是将第一个序列的顺序定义为“升序”,再对第二个序列求最大升序子序列(实际上是第一个序列的子序列),此时求出的子序列就是两个原序列的公共子序列。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| #include <iostream> #include <algorithm>
using namespace std;
const int N = 1e5 + 5;
int n, len = 0, x; int a[N], ind[N], q[N];
int bound(int x) { int l = 1, r = len; while (l < r) { int mid = (l + r) >> 1; if (ind[q[mid]] > ind[x]) r = mid; else l = mid + 1; } return l; }
int main() { cin >> n; for (int i = 1; i <= n; i ++ ) cin >> a[i];
for (int i = 1; i <= n; i ++ ) { cin >> x; ind[x] = i; } for (int i = 1; i <= n; i ++ ) { if (ind[a[i]] > ind[q[len]]) q[++ len] = a[i]; else q[bound(a[i])] = a[i]; } cout << len << endl; return 0; }
|