[解题记录] NOIP2015 提高组 子串
NOIP2015 提高组 子串#
题意简述#
有两个仅包含小写英文字母的字符串 和 。
现在要从字符串 中取出 个互不重叠的非空子串,然后依次连接起来得到一个新的字符串。请问有多少种方案可以使得这个新串与字符串 相等?
注意:子串取出的位置不同也认为是不同的方案。
解题思路#
为了保证无后效性,用 表示到了 的第一个字符,联想到 NOI Online 2022 T3 字符串,用 表示成功匹配了几个字符,用 表示使用了几个字串,但是发现这样不能轻松的转移,于是我们再加上一维 ,表示第 位是否选择
可以得到状态转移方程:
-
如果 ,
则 ,
分别表示不选和选,其中选又有三种情况,如果 选了,则可以新开一个或者沿用之前的字串,如果 没有选,那么只能新开一个
-
否则,
,不能选还要强行选,那么方案数归零
空间复杂度是 ,会爆空间,但是第一位可以用滚动数组优化
初始化为 ,因为后面三个为零的清况不会被更新到,但是又能算上一个方案
Code#
#include <bits/stdc++.h>
using namespace std;
const int N = 1e3 + 10, M = 2e2 + 10, mod = 1e9 + 7;
int f[2][M][M][2], n, m, c;
char a[N], b[M];
int main() {
scanf("%d%d%d", &n, &m, &c);
scanf("%s%s", a + 1, b + 1);
f[0][0][0][0] = 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 <= c; ++k) {
if (a[i] == b[j]) {
f[i & 1][j][k][0] = (f[(i - 1) & 1][j][k][0] + f[(i - 1) & 1][j][k][1]) % mod;
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]) % mod) % mod;
}
else {
f[i & 1][j][k][1] = 0;
f[i & 1][j][k][0] = (f[(i - 1) & 1][j][k][1] + f[(i - 1) & 1][j][k][0]) % mod;
}
}
printf("%d\n", (f[n & 1][m][c][1] + f[n & 1][m][c][0]) % mod);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现