当前位置: 首页 > article >正文

Educational Codeforces Round 21 G. Anthem of Berland(DP+KMP)

原题链接:G. Anthem of Berland


题目大意:


给出一个含有 ? ? ? 字符的字符串 s s s 和一个字符串 t t t,其中 ? ? ? 可以是 26 26 26 个字符中任意一个字符。

假设 s s s k k k ? ? ? ,现在要你求出在所有 2 6 k 26^{k} 26k 种可能的情况中, t t t s s s 出现的次数最大值为多少。

解题思路:


注意到 ∣ s ∣ ⋅ ∣ t ∣ ≤ 1 0 7 |s| \cdot |t| \leq 10^{7} st107,考虑某种 O ( n m ) O(nm) O(nm) 的做法。

定义 d p [ i ] dp[i] dp[i] 为只考虑 s s s 的前 i i i 个字符, t t t 能匹配的最大次数。

比较简单的想法就是考虑当前位置放和不放一整串 t t t 。(前提是能放)

d p [ i ] = max ⁡ { d p [ i − 1 ] , d p [ i − ∣ t ∣ ] + 1 } \begin{aligned} dp[i] = \max\{dp[i-1],dp[i-|t|]+1\} \end{aligned} dp[i]=max{dp[i1],dp[it]+1}

但是显然这不能考虑到所有的情况,比如当 s = a b a b a , t = a b a s=ababa,t=aba s=ababa,t=aba 时,我们可以利用前面放下的 t t t 串再做一次匹配,即:

s = [ a b a b a ] s=[ababa] s=[ababa]
t = [ a b a _ _ ] t=[aba\_\_] t=[aba__]
t = [ _ _ a b a ] t=[\_\_aba] t=[__aba]

此时 d p [ 5 ] dp[5] dp[5] 可以从 d p [ 3 ] dp[3] dp[3] 转移而来,发现这是一个 b o r d e r border border,考虑用 k m p kmp kmp n e x t next next 数组来优化这个寻找可以从哪个 b o r d e r border border 转移过程。

但能从 b o r d e r border border 开始转移的前提是,这个位置 必须 放了一个 t t t ,考虑下面的情况:

s = [ . . . a c [ a ] b a ] s=[...ac[a]ba] s=[...ac[a]ba]
t = [ . . . _ _ [ a ] b a ] t=[...\_\_[a]ba] t=[...__[a]ba]

此时虽然 [ a ] [a] [a] 位置确实是我们 t = a b a t=aba t=aba b o r d e r border border,但是其前面显然没有办法放下一个串 t t t,因而这个转移是不合法的。

所以我们还要考虑增加一个辅助数组 g [ i ] g[i] g[i] 表示,当前只考虑前 i i i 个位置,且第 i i i必须 放一个串 t t t 的最大方案数。

那么此时转移就是考虑要不要从 b o r d e r border border 处转移即可:

d p [ i ] = max ⁡ j ∈ b o r d e r { d p [ i ] , g [ j ] + 1 } \begin{aligned} dp[i] = \max_{j \in border}\{dp[i],g[j]+1\} \end{aligned} dp[i]=jbordermax{dp[i],g[j]+1}

那么直接暴力匹配即可,考虑当前如果不能放 t t t,则 d p [ i ] = d p [ i − 1 ] dp[i] = dp[i - 1] dp[i]=dp[i1]

否则考虑是否从 b o r d e r border border 转移而来,或者直接放下一个串 t t t

其中串 s s s 中的 ? ? ? 直接当通配符暴力匹配即可。

时间复杂度: O ( ∣ s ∣ ⋅ ∣ t ∣ ) O(|s| \cdot |t|) O(st)

#include <bits/stdc++.h>

using i64 = long long;

void solve() {
    std::string s, t;
    std::cin >> s >> t;

    int n = s.size(), m = t.size();
    s = '_' + s, t = '_' + t;

    std::vector<int> nxt(m + 1);
    for (int j = 2, p = 0; j <= m; ++j) {
        while (p && t[p + 1] != t[j]) p = nxt[p];
        p = nxt[j] = p + (t[p + 1] == t[j]);
    }

    auto check = [&](int l) {
        for (int i = 0; i < m; ++i) {
            if (s[l + i] != '?' && s[l + i] != t[i + 1]) {
                return false;
            }
        }
        return true;
    };

    std::vector<int> dp(n + 1), g(n + 1);
    for (int i = m; i <= n; ++i) {
        dp[i] = dp[i - 1];
        
        //假设能放串 t
        if (check(i - m + 1)) {
            g[i] = dp[i - m] + 1;
            for (int p = nxt[m]; p; p = nxt[p]) {
                g[i] = std::max(g[i], g[i - (m - p)] + 1);
            }
            dp[i] = std::max(dp[i], g[i]);
        }
    }

    std::cout << dp[n] << "\n";
}

signed main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);

    int t = 1;
    //std::cin >> t;
    while (t--) {
        solve();
    }

    return 0;
}

http://www.kler.cn/a/320432.html

相关文章:

  • 智谱AI清影升级:引领AI视频进入音效新时代
  • 三维测量与建模笔记 - 点特征提取 - 4.3 Harris特征点
  • 【C++动态规划】3148. 矩阵中的最大得分|1819
  • Spring Boot 接口防重复提交解决方案
  • 几何合理的分片段感知的3D分子生成 FragGen - 评测
  • Vue2教程002:Vue指令
  • 简易STL实现 | Set 的实现
  • python sqlite3数据库介绍(如何使用参数化查询防止SQL注入攻击)(直接通过网络让其他主机访问某台主机上的SQLite数据库是不被直接支持的)
  • vscode 配置django
  • 成都睿明智科技有限公司赋能商家高效变现
  • 从零开始的软件开发详解:数字药店系统源码与医保购药APP
  • 替换jar包中class文件
  • 6.使用 VSCode 过程中的英语积累 - Run 菜单(每一次重点积累 5 个单词)
  • 有毒有害气体检测仪的应用和性能_鼎跃安全
  • 一文通俗讲透 RAG 背后的逻辑,让 AI 回答更精准
  • 网络空间搜索引擎- FOFA的使用技巧总结
  • 用OPenCV分割视频
  • Python 烟花展示:使用 Pygame 创建绚丽的夜空
  • IEEE Transactions on Consumer Electronics (TCE)投稿指南
  • Redis 优化
  • gitlab-runner集成CI/CD完整项目部署
  • 智源研究院与百度达成战略合作 共建AI产研协同生态
  • php strtotime常见用法
  • NLP:命名实体识别及案例(Bert微调)
  • Github 2024-09-22 php开源项目日报 Top10
  • 零基础入门ComfyUI(一)初识ComfyUI