[NOIp2015]子串
Description
Luogu2679
求\(A\)中选出\(k\)个非空子串且连起来是\(B\)的方案数。
Solution
这个题可以仿照最长公共子序列来定义状态\(f_{i,j,k}\)表示\(A\)串的前\(i\)个和\(B\)串的前\(j\)个匹配,且用了\(k\)个子串,并且必须选\(A_i\)。但是这样并不是很好转移。
所以我们添加一个辅助状态\(s_{i,j,k}\)表示\(A\)串的前\(i\)个和\(B\)串的前\(j\)个匹配,且用了\(k\)个子串,但是不一定选\(A_i\)。于是就有如下几种转移:
若\(A_i = B_j\),则\(f_{i,j,k} = f_{i-1,j-1,k} + s[i-1][j-1][k-1]\)(分别对应\(A_i\)和\(A_{i-1}\)组合成一个子串或者是单独成一个子串),否则\(f_{i,j,k} = 0\)。
而无论如何,\(s_{i,j,k} = f_{i, j, k} + s_{i-1,j,k}\)
Code
#include <cstdio>
typedef long long ll;
const int N = 1010;
const int M = 210;
const ll MOD = 1e9 + 7;
ll f[M][M][2];
char a[N], b[M];
int n, m, k;
int main() {
scanf("%d%d%d", &n, &m, &k);
scanf("%s", a+1); scanf("%s", b+1);
f[0][0][0] = f[0][0][1] = 1;
for (int i = 1; i <= n; ++i)
for (int j = m; j; --j)
for (int K = k; K; --K) {
if (a[i] == b[j])
f[j][K][0] = (f[j-1][K][0] + f[j-1][K-1][1]) % MOD;
else f[j][K][0] = 0;
f[j][K][1] = (f[j][k][1] + f[j][K][0]) % MOD;
}
printf("%lld\n", f[m][k][1] % MOD);
}
Note
这个题我一开始提交的时候写的是%I64d
错了一次,后来又因为忘记取模错了一次。这些小问题还是要仔细。