跳转至

洛谷-P1439 【模板】最长公共子序列(LCS优化版本)

题目描述

给出 1,2,\ldots,n1,2,…,n 的两个排列 P_1*P*1 和 P_2*P*2 ,求它们的最长公共子序列。

输入格式

第一行是一个数 n*n*。

接下来两行,每行为 n*n* 个数,为自然数 1,2,\ldots,n1,2,…,n 的一个排列。

输出格式

一个数,即最长公共子序列的长度。

输入输出样例

输入 #1

5 
3 2 1 4 5
1 2 3 4 5

输出 #1

3

说明/提示

  • 对于 50\%50% 的数据, n \le 10^3*n*≤103;
  • 对于 100\%100% 的数据, n \le 10^5*n*≤105。

#include <bits/stdc++.h>

using namespace std;

int n;
vector<int> seq(100005), discrete(100005), d(100005);

int solve()
{
    d[1] = discrete[seq[0]];
    int len = 1;
    for (int i = 1; i < n; ++i) {
        int target = discrete[seq[i]];

        int left = 1, right = len + 1;
        while (left < right) {
            int mid = left + ((right - left) >> 1);
            if (d[mid] < target) left = mid + 1;
            else right = mid;
        }
        if (left == len + 1) d[++len] = target;
        else d[left] = target;
    }

    return len;
}

int main()
{
    std::ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);

    cin >> n;
    for (int i = 0; i < n; ++i) {
        int num; cin >> num;
        discrete[num] = i + 1;
    }

    for (int i = 0; i < n; ++i) {
        cin >> seq[i];
    }

    cout << solve() << endl;

    return 0;
}

两个序列的元素都是从1到n的n个数,打乱顺序排列,比如例子:

3 2 1 4 5
1 2 3 4 5

现在我们用一种办法映射,将3映射成a,2映射成b,以此类推,则第一个序列变成了:

a b c d e

然后看第二个序列按照这个规则的映射:

c b a d e

两个的公共子序列,无论这个子序列怎么从第一个序列里面选,它都是升序的,所以只需要从第二个序列找LIS即可,于是就可以用二分优化了。