【题意分析】
这种dp题也就是按照套路来,先设一个四维的状态:dp[i][j][k][l]
就是第一个串前i个,第二个串前j个,取了k段,第二个串当前位置取不取(0不取1取)的方案总数
计数dp嘛,分类讨论:
如果枚举的位置两个字符相同,那么就表明可以取或不取
d p i , j , k , 0 = d p i − 1 , j , k , 0 + d p i − 1 , j , k , 1 dp_{i,j,k,0}=dp_{i-1,j,k,0}+dp_{i-1,j,k,1} dpi,j,k,0=dpi−1,j,k,0+dpi−1,j,k,1
d p i , j , k , 1 = d p i − 1 , j − 1 , k − 1 , 1 + d p i − 1 , j − 1 , k − 1 , 0 + d p i − 1 , j − 1 , k , 1 dp_{i,j,k,1}=dp_{i-1,j-1,k-1,1}+dp_{i-1,j-1,k-1,0}+dp_{i-1,j-1,k,1} dpi,j,k,1=dpi−1,j−1,k−1,1+dpi−1,j−1,k−1,0+dpi−1,j−1,k,1
//对第二个naive方程的解释:这个字符取了,可能上个字符取了,连成一段或者另起一段,或者上个字符不取,那么必定另起一段。
如果不同,那么就只能不取
d p i , j , k , 0 = d p i − 1 , j , k , 0 + d p i − 1 , j , k , 1 dp_{i,j,k,0}=dp_{i-1,j,k,0}+dp_{i-1,j,k,1} dpi,j,k,0=dpi−1,j,k,0+dpi−1,j,k,1
d p i , j , k , 1 = 0 dp_{i,j,k,1}=0 dpi,j,k,1=0
就好了,然后很明显第一维可以滚动掉(大部分计数dp都可以滚动掉一维),就可以过了
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <algorithm>
#define MAXN 1010
#define MAXM 205
#define qy 1000000007
using namespace std;
char s1[MAXN], s2[MAXN];
int dp[2][MAXM][MAXM][2], n, m, K, now, pre;
int main () {
scanf ("%d%d%d", &n, &m, &K), scanf ("%s", s1 + 1), scanf ("%s", s2 + 1);
dp[0][0][0][0] = dp[1][0][0][0] = 1, now = 0, pre = 1;
for (register int i = 1; i <= n; i++) {
now ^= 1, pre ^= 1;
for (register int j = 1; j <= m; j++)
for (register int k = 1; k <= K; k++) {
if (s1[i] == s2[j]) {
dp[now][j][k][0] = (dp[pre][j][k][0] + dp[pre][j][k][1]) % qy;
dp[now][j][k][1] = ((dp[pre][j - 1][k - 1][0] + dp[pre][j - 1][k - 1][1]) % qy + dp[pre][j - 1][k][1]) % qy;
}
else {
dp[now][j][k][0] = (dp[pre][j][k][0] + dp[pre][j][k][1]) % qy;
dp[now][j][k][1] = 0;
}
}
}
return printf ("%d\n", (dp[n & 1][m][K][0] + dp[n & 1][m][K][1]) % qy), 0;
}