题意:
给定两个串A, B。现在要从字符串 A 中取出 k 个互不重叠的非空子串,然后把这 k 个子串按照其在字符串 A 中出现的顺序依次连接起来得到一个新的字符串。请问有多少种方案可以使得这个新串与字符串 B 相等?
思路:
-
状态设计:
A串的第 i 位,匹配到了B串第 j 位,使用了k个子串。
可以得出dp数组:f[i][j][k][u]。
-
状态转移:
第 i 个字符如果跟第 j 个字符相同, 则对于该字符有两种决策, 可以使用或者不使用
1.当前使用 f[i][j][k][1] = f[i - 1][j - 1][k][1] + f[i - 1][j - 1][k - 1][0] + f[i - 1][j - 1][k - 1][0];
2: 当前不用 f[i][j][j][0] = f[i - 1][j][k][1] + f[i - 1][j][k][0];
第 i 个字符如果跟第 j 个字符相同, 则对于该字符只有一种决策, 不使用
f[i][j][j][0] = f[i - 1][j][k][1] + f[i - 1][j][k][0];
当前第i个字符不能使用 所以
f[i][j][k][1] = 0
-
内存优化:
对于上述内存为 1000 * 200 * 200 * 2, 内存肯定不会爆。
我们发现状态转移只用到了 i 和 i - 1。
所以可以将一维优化到 2
对于 i - 1 可以表示成 (i - 1) & 1
对于 i 可以表示成 i & 1
代码:
#include <bits/stdc++.h> #define int long long const int MOD = 1e9 + 7; int f[2][220][220][2]; signed main() { std::ios::sync_with_stdio(false); std::cin.tie(nullptr), std::cout.tie(nullptr); int n, m, q; std::cin >> n >> m >> q; std::string a, b; std::cin >> a >> b; a = '!' + a; b = '!' + b; f[0][0][0][0] = 1; f[1][0][0][0] = 1; for (int i = 1; i <= n; ++i) { for (int j = 1; j <= m; ++j) { for (int k = 1; k <= q; ++k) { if (a[i] == b[j]) { f[i & 1][j][k][1] = (f[(i - 1) & 1][j - 1][k][1] + f[(i - 1) & 1][j-1][k-1][0]) + f[(i - 1) & 1][j - 1][k - 1][1]; f[i & 1][j][k][0] = f[(i - 1) & 1][j][k][1] + f[(i - 1) & 1][j][k][0]; f[i & 1][j][k][1] %= MOD; f[i & 1][j][k][0] %= MOD; } else { f[i & 1][j][k][0] = f[(i - 1) & 1][j][k][1] + f[(i - 1) & 1][j][k][0]; f[i & 1][j][k][1] = 0; f[i & 1][j][k][0] %= MOD; } } } } std::cout << (f[n & 1][m][q][1] + f[n & 1][m][q][0]) % MOD << '\n'; return 0; }
标签:子串,std,NOIP2015,int,P2679,cin,字符串,个字符 From: https://www.cnblogs.com/MCJ-YMR/p/16824826.html