P2679 子串
思路
定义状态 f(i,j,k)为以A的第 i 个字符为结尾取出 k 段后在字符串B匹配到 j 的方案数。则可知当A[i] != B[ j]时,该状态方案数为0 ,当A[i]==B[ j]时,A[ i ] 可以选择重启一段或者跟在上一段后面。情况2为 f(i-1,j-1,k),情况1是所有 f(x,j-1,k-1)之和,这里的x为 i 的任意一个前驱。利用前缀和优化所有前驱求和,滚动数组优化空间(k状态只和k-1状态有关)。
代码
#include<iostream>
#include<cstring>
#define MAXN 1007
#define mod 1000000007
using namespace std;
int n, m, k, dp[2][MAXN][MAXN], sum[2][MAXN][MAXN];
char A[MAXN], B[MAXN];
int main(void)
{
cin >> n >> m >> k;
cin >> &A[1] >> &B[1];
for (int i = 0; i <= n; i++)
sum[1][i][0] = 1;
int cr = 0;
for (int K = 1; K <= k; K++, cr ^= 1)
{
memset(dp[cr], 0, sizeof(dp[cr]));
memset(sum[cr], 0, sizeof(sum[cr]));
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
if (A[i] == B[j])
dp[cr][i][j] = (dp[cr][i - 1][j - 1] + sum[cr ^ 1][i - 1][j - 1]) % mod;
sum[cr][i][j] = (sum[cr][i - 1][j] + dp[cr][i][j]) % mod;
}
}
}
cout << sum[cr ^ 1][n][m];
return 0;
}

浙公网安备 33010602011771号