[CF10D] LCIS - dp
DESCRIPTION
求两个串的最长公共上升子序列 (n,m < 500)
SOLUTION
关键是在设置状态的时候,强制以某一维参量为结尾
设 (f[i][j]) 表示选取分别选取前 i,j 个元素,并且以 (b[j]) 结尾,组成的 LCIS 最长是多少
转移的时候,只需要考虑 ai,bj 的情况
如果 ai=bj,那么一方面可以放弃 i,从 (i-1,j) 转移,另一方面也可以找一个更小更前面的 t,从 (i-1,t) 转移,答案获得 1 的增量
否则,只能从 (i-1,j) 转移
记录一下转移来源,然后递归输出答案即可
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 505;
int n, m, a[N], b[N], f[N][N], from[N][N];
signed main()
{
ios::sync_with_stdio(false);
cin >> n;
for (int i = 1; i <= n; i++)
cin >> a[i];
cin >> m;
for (int i = 1; i <= m; i++)
cin >> b[i];
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
f[i][j] = f[i - 1][j];
if (f[i][j])
from[i][j] = j;
if (a[i] == b[j])
{
if (f[i][j] < 2)
f[i][j] = 1, from[i][j] = 0;
}
if (a[i] == b[j])
{
for (int k = 1; k < j; k++)
if (b[k] < b[j])
{
f[i][j] = max(f[i][j], f[i - 1][k] + 1);
if (f[i][j] == f[i - 1][k] + 1 && f[i][j] > 1)
from[i][j] = k;
}
}
}
}
// for (int i = 1; i <= n; i++)
// {
// for (int j = 1; j <= m; j++)
// {
// cout << f[i][j] << "(" << from[i][j] << ")"
// << " ";
// }
// cout << endl;
// }
int p = 0;
for (int i = 1; i <= m; i++)
if (f[n][i] > f[n][p])
p = i;
cout << f[n][p] << endl;
set<int> ans;
for (int i = n; i >= 1 && p; i--)
ans.insert(p), p = from[i][p];
for (auto i : ans)
cout << b[i] << " ";
cout << endl;
}