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;
}