「HAOI2010」最長公共子序列-DP
阿新 • • 發佈:2018-12-22
Decription
給定兩個字串,求他們最長的公共子序列長度,以及最長公共子序列個數。
Solution
最長公共序列直接 DP即可。重點是如何求出最長公共子序列個數。
設
表示第一個串匹配到
,第二個串匹配到
的最長公共子序列長度。
則表示最長公共子序列個數。
考慮 的轉移
那麼 則加上 轉移的來源的 即可。
但是有一個特殊情況:
時, 與 重複轉移了 因此要減去。
推薦FlashHu的題解,還有圖示。
// luogu-judger-enable-o2
#include <bits/stdc++.h>
using namespace std;
const int maxn = 5005, mod = 100000000;
int n, m, f[2][maxn], g[2][maxn];
char s[maxn], t[maxn];
void inc(int &a, int b)
{
a += b;
if (a >= mod) a -= mod;
}
void dec(int &a, int b)
{
a -= b;
if (a < 0) a += mod;
}
int main()
{
scanf("%s", s + 1); n = strlen(s + 1) - 1;
scanf("%s", t + 1); m = strlen(t + 1) - 1;
fill(g[0], g[0] + m + 1, 1);
for (int k = 1; k <= n; ++k) {
int i = k & 1;
g[i ^ 1][0] = g[i][0] = 1;
for (int j = 1; j <= m; ++j) {
f[i][j] = max(f[i ^ 1][j], f[i][j - 1]);
if (s[k] == t[j]) f[i][j] = max(f[i][j], f[i ^ 1][j - 1] + 1);
}
for (int j = 1; j <= m; ++j) {
g[i][j] = 0;
if (f[i][j] == f[i ^ 1][j]) inc(g[i][j], g[i ^ 1][j]);
if (f[i][j] == f[i][j - 1]) inc(g[i][j], g[i][j - 1]);
if (f[i][j] == f[i ^ 1][j - 1])
dec(g[i][j], g[i ^ 1][j - 1]);
if (f[i][j] == f[i ^ 1][j - 1] + 1 && s[k] == t[j])
inc(g[i][j], g[i ^ 1][j - 1]);
}
}
printf("%d\n%d\n", f[n & 1][m], g[n & 1][m]);
return 0;
}