[解题记录] NOI Online 2022 入门组 字符串
NOI Online 2022 入门组 字符串#
题意简述#
给定两个字符串 和 和一个初始为空的字符串 ,其中 长度为 ,且只由 0
, 1
, -
三种字符构成(注:这里的第三种字符是减号), 然后进行 次操作, 每次会取出 的第一个字符(记为 ),并将其从 中删去。如果 ,则要删去 的开头字符或结尾字符(数据保证删去后 不为空)。将 加入到 的末尾。问将 变成 的方案数。
解题思路#
首先不难想到一个 的爆搜,就是枚举遇到减号时的决策,这样可以拿
看到题目的数据范围,以及题目要我们求方案数,就联想到 DP, 我们定义状态 表示 操作到第 个, 成功匹配了 的前 个数, 前面要删除 个数,后面要删除 个数的方案,那么状态转移方程就是 :
- 若 ,
- 若 ,
- 若 且 且 ,
复杂度是 的,不能通过所有数据,但是我们发现其实最后一维完全没有必要记录,因为每次操作完后, 的字符数是确定的,所以只要知道前面有几个要删除,成功匹配了几个,状态就是唯一确定的,去掉一维后复杂度就变成 的,但是实现一下就会发现 DP 要处理的细节非常多,我们所以可以写 记忆化搜索 !
Code#
DP
#include <bits/stdc++.h>
using namespace std;
const int N = 410, mod = 1e9 + 7;
int f[N][N][N], n, m, T;
char s[N], t[N];
int main() {
scanf("%d", &T);
while (T--) {
scanf("%d%d%s%s", &n, &m, s + 1, t + 1);
memset(f, 0, sizeof(f));
int sum = 0;
f[0][0][0] = 1;
for (int i = 1; i <= n; ++i) {
if (s[i] == '-') sum ++;
for (int j = 0; j <= m; ++j) {
for (int k = 0; k <= n; ++k) {//结尾
int l = i - 2 * sum - k - j;
if (l < 0) continue;
if (s[i] == '-') f[i][j][k] = (f[i - 1][j][k + 1] + f[i - 1][j][k]) % mod;//删左和删右
else {
if (k != 0) f[i][j][k] = (f[i][j][k] + f[i - 1][j][k - 1]) % mod;//放后面
else if (s[i] == t[j]) f[i][j][k] = (f[i][j][k] + f[i - 1][j - 1][k]) % mod;
if (!k && !j) f[i][j][k] = (f[i][j][k] + f[i - 1][j][k]) % mod;
}
}
}
}
printf("%d\n", f[n][m][0]);
}
return 0;
}
dfs
#include <bits/stdc++.h>
using namespace std;
const int N = 410, mod = 1e9 + 7;
int f[N][N][N], n, m, T;
char s[N], t[N];
int dfs(int i, int j, int x, int y) {//表示操作到s[i],匹配成功j个,前面要删x个,后面删除y个走下去成功的方案
if (i > n) return j == m && !x && !y;
if (~f[i][j][x]) return f[i][j][x];
int val = 0;
if (s[i] == '-') {
if (x) val = (val + dfs(i + 1, j, x - 1, y)) % mod;//删前面的
if (y) val = (val + dfs(i + 1, j, x, y - 1)) % mod;//删后面的
}
else {
val = (val + dfs(i + 1, j, x, y + 1)) % mod;//直接放到后面
if (!j && !y) val = (val + dfs(i + 1, j, x + 1, y)) % mod;//如果中间和后面都是空的
if (s[i] == t[j + 1] && !y) val = (val + dfs(i + 1, j + 1, x, y)) % mod;//如果匹配成功
}
return f[i][j][x] = val;
}
int main() {
scanf("%d", &T);
while (T--) {
memset(f, -1, sizeof(f));
scanf("%d%d%s%s", &n, &m, s + 1, t + 1);
printf("%d\n", dfs(1, 0, 0, 0));
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现