经典的 LCS 求方案数。
第一问很简单,直接 (O(n^2)) 求出序列 LCS 长度即可。
对于第二问,直接在转移的时候分类讨论一下,最后处理重复计算的情况就可以了。
注意这一题卡空间,需要开滚动数组优化空间。
#include <bits/stdc++.h>
#define DEBUG fprintf(stderr, "Passing [%s] line %d
", __FUNCTION__, __LINE__)
#define File(x) freopen(x".in","r",stdin); freopen(x".out","w",stdout)
using namespace std;
typedef long long LL;
typedef pair <LL, LL> PII;
typedef pair <LL, PII> PIII;
const LL INF = 0x3f3f3f3f, N = 5003, mod = 100000000;
LL n, m;
LL dp[2][N], g[2][N];
char s[N], t[N];
int main()
{
//File("");
scanf("%s", s + 1);
scanf("%s", t + 1);
n = strlen(s + 1) - 1, m = strlen(t + 1) - 1;
g[1][0] = 1;
for (LL i = 0; i <= m; i+=1) g[0][i] = 1;
for (LL i = 1; i <= n; i+=1)
for (LL j = 1; j <= m; j+=1)
{
dp[i & 1][j] = dp[i - 1 & 1][j], g[i & 1][j] = g[i - 1 & 1][j] % mod;
if (dp[i & 1][j] == dp[i & 1][j - 1])
(g[i & 1][j] += g[i & 1][j - 1]) %= mod;
else if (dp[i & 1][j - 1] > dp[i & 1][j])
dp[i & 1][j] = dp[i & 1][j - 1], g[i & 1][j] = g[i & 1][j - 1] % mod;
if (s[i] == t[j])
{
if (dp[i - 1 & 1][j - 1] + 1 > dp[i & 1][j])
dp[i & 1][j] = dp[i - 1 & 1][j - 1] + 1, g[i & 1][j] = g[i - 1 & 1][j - 1] % mod;
else if (dp[i - 1 & 1][j - 1] + 1 == dp[i & 1][j])
(g[i & 1][j] += g[i - 1 & 1][j - 1]) %= mod;
}
else if (dp[i & 1][j - 1] == dp[i - 1 & 1][j] && dp[i - 1 & 1][j] == dp[i - 1 & 1][j - 1])
g[i & 1][j] -= g[i - 1 & 1][j - 1]; //重复转移的情况
}
printf("%lld
%lld
", dp[n & 1][m], (g[n & 1][m] % mod + mod) % mod);
return 0;
}