zoukankan      html  css  js  c++  java
  • 排列LCS问题

    题目描述

    给你两个长度为 (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] e P_2[j]),则 (d[i,j]) 不能转移到 (d[i+1,j+1]),因为目标函数不能增加。这样,我们应该只关心满足 (P_1[i] = P_2[j]) 的状态 (d[i,j]),也就是说,可以把状态转移方程写成:

    [d[i,j] = max { d[i',j'] } + 1, ext{ } P_1[i] = P_2[j], ext{ } i' gt i, j' gt 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;
    }
    
    
  • 相关阅读:
    51 Nod 1086 多重背包问题(单调队列优化)
    51 Nod 1086 多重背包问题(二进制优化)
    51 Nod 1085 01背包问题
    poj 2559 Largest Rectangle(单调栈)
    51 Nod 1089 最长回文子串(Manacher算法)
    51 Nod N的阶乘的长度 (斯特林近似)
    51 Nod 1134 最长递增子序列(经典问题回顾)
    51 Nod 1020 逆序排列
    PCA-主成分分析(Principal components analysis)
    Python中cPickle
  • 原文地址:https://www.cnblogs.com/quanjun/p/13193561.html
Copyright © 2011-2022 走看看