CF808G Anthem of Berland 解题报告
Description
给定 串和 串,其中 串包含小写字母和问号, 串只包含小写字母。
假设共有 个问号。
你需要给把每个问号变成一个小写字母,共有 种可能。
对于每种可能,设 匹配 的次数为 ,请输出 。
Solution
发现 , 显然可以对于 的每个位置对 进行暴力匹配。
于是这是个线性问题,考虑 dp。用 表示 在 的前 个位置出现的最大次数。
如果当前位置能够匹配,显然 可以从 转移。但这是不够的,因为 是可以重叠放的,而且仅仅有一个 数组是不够的,于是我们可以用 表示第 个位置一定选的最大匹配数。枚举 的 border,每次更新 即可。
CODE

#include<bits/stdc++.h> using namespace std; inline int read() { int x = 0, f = 1; char c = getchar(); while (c < '0' || c > '9') {if (c == '-') f = -f; c = getchar();} while (c >= '0' && c <= '9') {x = (x << 3) + (x << 1) + (c ^ 48); c = getchar();} return x * f; } const int N = 1e5 + 10; int n, m, f[N], g[N], nxt[N]; char s[N], t[N]; inline bool chk (int p) { if (p < m) return false; for (int i = 1; i <= m; ++ i) if (s[p-i+1] != t[m-i+1] && s[p-i+1] != '?') return false; return true; } int main () { scanf("%s", s + 1); scanf("%s", t + 1); n = strlen(s + 1); m = strlen(t + 1); nxt[1] = 0; for (int i = 2, j = 0; i <= m; ++ i) { while (j && t[i] != t[j+1]) j = nxt[j]; if (t[i] == t[j+1]) ++ j; nxt[i] = j; } for (int i = 1; i <= n; ++ i) { f[i] = f[i-1]; if (chk(i)) { g[i] = f[i-m] + 1; for (int j = nxt[m]; j; j = nxt[j]) g[i] = max(g[i], g[i-(m-j)] + 1); f[i] = max(f[i], g[i]); } } printf("%d\n", f[n]); return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构