Codeforces 10D LCIS

https://codeforces.com/problemset/problem/10/D

题意:求s串和t串的最长上升公共子序列,要求出方案

题解:

\(f_{i,j}\) 表示 \(s[1...i]\)\(t[1...j]\) 匹配且匹配的串末尾为 \(t_j\) 的最长串

转移即是:

  • \(f_{i,j}\) 可以从 \(f_{i-1,j}\) 无条件转移
  • \(f_{i,j}\) 可以从 \(max(f_{i-1,k})+1 ~ (k \le j ~and~ s_i = t_j ~and~ s_i \le t_k)\) 转移

然后转移的同时记录从 \(t\) 串的哪个位置转移而来就可以计算方案,需要耗费多一倍的空间

代码:

/*================================================================
*
*   创 建 者: badcw
*   创建日期: 2020/6/15 21:13
*
================================================================*/
#include <bits/stdc++.h>

#define ll long long
using namespace std;

const int maxn = 505;
const int mod = 1e9+7;
ll qp(ll a, ll n, ll mod = ::mod) {
    ll res = 1;
    while (n > 0) {
        if (n & 1) res = res * a % mod;
        a = a * a % mod;
        n >>= 1;
    }
    return res;
}

int n, m;
int s[maxn], t[maxn];
int dp[maxn][maxn];
int tp[maxn][maxn];

int main(int argc, char* argv[]) {
    scanf("%d", &n);
    for (int i = 1; i <= n; ++i) scanf("%d", &s[i]);
    scanf("%d", &m);
    for (int i = 1; i <= m; ++i) scanf("%d", &t[i]);
    for (int i = 1; i <= n; ++i) {
        int mx = 0;
        for (int j = 1; j <= m; ++j) {
            tp[i][j] = tp[i - 1][j];
            dp[i][j] = dp[i - 1][j];
            if (s[i] > t[j] && dp[i][mx] < dp[i][j]) mx = j;
            else if (s[i] == t[j] && dp[i][mx] + 1 > dp[i][j]) dp[i][j] = dp[i][mx] + 1, tp[i][j] = mx;
        }
    }
    int mx = 0;
    for (int i = 1; i <= m; ++i) {
        if (dp[n][mx] < dp[n][i]) {
            mx = i;
        }
    }
    printf("%d\n", dp[n][mx]);
    vector<int> res;
    while (mx != 0) {
        res.push_back(t[mx]);
        mx = tp[n][mx];
    }
    reverse(res.begin(), res.end());
    for (auto i : res) {
        printf("%d ", i);
    }
    return 0;
}
posted @ 2020-06-16 15:21  badcw  阅读(182)  评论(0编辑  收藏  举报