这题真的是。。不想说了,刚开始不敢加第三维,然后看题解发现第一维可以压掉。。
然后如果我们设$f[i,j,k]$为$A$匹配到$i$, $B$匹配到$j$, 已经分了$k$个部分的方案总数,在转移的时候发现不能判断某一个字符取了还是没取,那么加一维, $f[i, j, k, 0]$表示不取,$f[i, j, k, 0]$表示取。
那么分别转移:
$$f[i,j,k,0]=f[i-1,j,k,1]+f[i-1,j,k,0]$$
$$f[i,j,k,1] = f[i-1,j-1,k,1] + f[i-1,j-1,k-1,1] + f[i-1,j-1,k-1,0]$$
在$A[i]==B[j]$时,才能更新$f[i,j,k,1]$
初始化时$f[i,1,1,0] = s$, $s$为前$i$个字符能匹配$B[1]$多少次,那么每次枚举,都$f[i,1,1,0]=s$, 如果当前为能够匹配,则$f[i,1,1,1] = 1,s+=1$
最后答案是$f[n,m,k,0]+f[n,m,k,1]$
注意本题要取模,并且要计算空间复杂度不然会爆炸
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define ms(i, j) memset(i, j, sizeof i)
#define LL long long
using namespace std;
const int MAXN = 1000 + 5, MAXM = 200 + 5, MO = 1000000007;
int n, m, k;
char a[MAXN], b[MAXM];
LL f[MAXM][MAXM][2], g[MAXM][MAXM][2];
void clean() {
ms(f, 0), ms(g, 0);
}
void init() {
clean();
scanf("%s%s", a+1, b+1);
}
void solve() {
int s = 0;
for (int i=1;i<=n;i++) {
//init
f[1][1][0] = s;
if (a[i]==b[1]) f[1][1][1] = 1, s++;
//start
for (int j=2;j<=m;j++)
for (int kk=1;kk<=k;kk++) {
f[j][kk][0] = (g[j][kk][1]+g[j][kk][0])%MO;
if (a[i]==b[j]) f[j][kk][1] = (g[j-1][kk][1]+g[j-1][kk-1][1]+g[j-1][kk-1][0])%MO;
}
//clean
for (int j=1;j<=m;j++)
for (int kk=1;kk<=k;kk++) {
g[j][kk][0] = f[j][kk][0], f[j][kk][0] = 0;
g[j][kk][1] = f[j][kk][1], f[j][kk][1] = 0;
}
}
printf("%lld\n", (g[m][k][0]+g[m][k][1])%MO);
}
int main() {
#ifndef ONLINE_JUDGE
freopen("1.in", "r", stdin);freopen("1.out", "w", stdout);
#endif
while (scanf("%d%d%d", &n, &m, &k)==3) init(), solve();
return 0;
}