- 2015
T5
- @ 2025-10-6 16:08:38
#include<bits/stdc++.h>
using namespace std;
const int N = 1010, M = 210, mod = 1e9 + 7;
int n, m, K;
string a, b;
int f[M][M], sum[M][M];
int main()
{
cin >> n >> m >> K;
cin >> a >> b;
a = " " + a;
b = " " + b;
f[0][0] = 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]) sum[j][k] = (sum[j - 1][k] + f[j - 1][k - 1]) % mod;
else sum[j][k] = 0;
f[j][k] = (f[j][k] + sum[j][k]) % mod;
}
cout << f[m][K] << endl;
return 0;
}
/*
状态表示: f[i, j, k] 来表示只用s的前i个字母,选取了k段,可以匹配t的前j个字母的方案数
状态计算:
用s[i] : 那么可以按s[i]所在的一段一共有多少个字母继续分类:
如果有d个字母,则方案数是 f[i - d, j - d, k - 1];
不用s[i]: f[i, j, k] = f[i - 1, j, k];
f[i, j, k] = f[i - 1, j, k] + sum(f[i - d, j - d, k - 1]);
d的满足条件: s[i - d + 1] == t[j - d + 1]即可一直往前枚举。
以上的时间复杂度为 O(nm^2k)
会超时,继续优化
f[i, j, k]的第二项表达式和f[i - 1, j - 1, k]的第二项表达式很像。
令 sum(i, j, k) = sum(f[i - d, j - d, k - 1])
s[i] == t[j] sum(i, j, k) = sum(i - 1, j - 1, k) + f[i - 1, j - 1, k - 1]
s[i] != t[j] sum(i, j, k) = 0;
所以其实这个sum就是一个前缀和,除了d = 1时要新算之外,其他情况其实已经求过了。
2*n*m*k = 2*1000*200^2*4字节=300M, 会超空间。
f[i, j, k] 和 sum(i, j, k) 均只和i - 1层有关系 反着遍历,枚举j和k即可。
*/
0 条评论
目前还没有评论...