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;
}
"educational codeforces round 103 (rated for div. 2)"是一个Codeforces平台上的教育性比赛,专为2级选手设计评级。以下是有关该比赛的回答。 "educational codeforces round 103 (rated for div. 2)"是一场Codeforces平台上的教育性比赛。Codeforces是一个为程序员提供竞赛和评级的在线平台。这场比赛是专为2级选手设计的,这意味着它适合那些在算法和数据结构方面已经积累了一定经验的选手参与。 与其他Codeforces比赛一样,这场比赛将由多个问题组成,选手需要根据给定的问题描述和测试用例,编写程序来解决这些问题。比赛的时限通常有两到三个小时,选手需要在规定的时间内提交他们的解答。他们的程序将在Codeforces的在线评测系统上运行,并根据程序的正确性和效率进行评分。 该比赛被称为"educational",意味着比赛的目的是教育性的,而不是针对专业的竞争性。这种教育性比赛为选手提供了一个学习和提高他们编程技能的机会。即使选手没有在比赛中获得很高的排名,他们也可以从其他选手的解决方案中学习,并通过参与讨论获得更多的知识。 参加"educational codeforces round 103 (rated for div. 2)"对于2级选手来说是很有意义的。他们可以通过解决难度适中的问题来测试和巩固他们的算法和编程技巧。另外,这种比赛对于提高解决问题能力,锻炼思维和提高团队合作能力也是非常有帮助的。 总的来说,"educational codeforces round 103 (rated for div. 2)"是一场为2级选手设计的教育性比赛,旨在提高他们的编程技能和算法能力。参与这样的比赛可以为选手提供学习和进步的机会,同时也促进了编程社区的交流与合作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

柠檬味的橙汁

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值