CF808G Anthem of Berland 解题报告

Description

给定 s 串和 t 串,其中 s 串包含小写字母和问号,t 串只包含小写字母。

假设共有 k 个问号。

你需要给把每个问号变成一个小写字母,共有 26k 种可能。

对于每种可能,设 t 匹配 s 的次数为 fi,请输出 max(fi)

Solution

发现 |s||t|107, 显然可以对于 s 的每个位置对 t 进行暴力匹配。

于是这是个线性问题,考虑 dp。用 fi 表示 ts 的前 i 个位置出现的最大次数。

如果当前位置能够匹配,显然 fi 可以从 fim 转移。但这是不够的,因为 t 是可以重叠放的,而且仅仅有一个 f 数组是不够的,于是我们可以用 gi 表示第 i 个位置一定选的最大匹配数。枚举 t 的 border,每次更新 gi 即可。

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;
}
View Code
复制代码

 

posted @   LikC1606  阅读(20)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示