原题链接

题意

  • 第一行给我们一串长为s,只包含小写字母与问号的字符串A,第二行给我们一个长为t只有小写字母的字符串B, 同时满足 $ s * t \le 1e7 $

  • 我们可以把问号变成任意的字母,我们需要求出如何变换才能使A串包含最多次B串(可以重叠),输出这个最大值

思路

  • 单模式串匹配我们可以想到KMP算法或者前缀函数

  • 一开始贪心考虑将“?”设置为100%匹配,但是显然这是行不通的,比如下面这组数据

\[acc??cca \\
acca
\]

显然答案是2,A应该变成如果kmp算法来贪心匹配,到第二个问号的时候,会将?设置为c,那么就和正确结果不符了

  • 因为两字符串长度乘积最多为一千万,所以可以考虑DP,我们先预处理出B串的前缀函数值,然后给B串添加一个分隔符#之后,处理出前缀函数的自动机
\[prem[i][j]
\]

也就是在当前前缀函数值为i的情况下,下一个字符为j时转移到的前缀函数值。

  • 这样我们设置DP数组
\[dp[i][j]
\]

为当前在A串的i位置,匹配到B串的j位置时(也就是前缀函数为j)的最大匹配数。为了便于理解我们初始化dp[0][0]为0,其他值为-1,转移方程为

\[dp[i][prem[j][k]] = max_{'a' \le k \le 'z'}\{max_{0 \le j \le t}\{dp[i - 1][j] + (prem[j][k] == t)\}\} (A[i] = '?')
\\
dp[i][prem[j][A[i]]] = max_{0 \le j \le t}\{dp[i - 1][j] + (prem[j][A[i]] == t)\} (A[i] \ne '?')
\]
  • 最后取dp[s][i]中的最大值即可,对于空间问题,可以将两维写在一维中,或者使用滚动数组

AC代码

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm> using namespace std; const int N = 100000; char ss[N + 5], sss[N + 5];
int prem[N + 5][26];
int pf[N + 5];
int dp[2][N + 5];
int len; void prefun(char *s)
{
len = strlen(s + 1);
pf[0] = pf[1] = 0;
for (int i = 2; i <= len; ++i)
{
pf[i] = 0;
int l = pf[i - 1];
while (l && s[l + 1] != s[i])
{
l = pf[l];
}
if (s[l + 1] == s[i])
{
pf[i] = l + 1;
}
}
} void preatm(char *s)
{
s[++len] = '#';
for (int i = 0; i < len; ++i)
{
for (int j = 0; j < 26; ++j)
{
if (i && 'a' + j != s[i + 1])
{
prem[i][j] = prem[pf[i]][j];
}
else
{
prem[i][j] = i + ('a' + j == s[i + 1]);
}
}
}
} int main()
{
scanf("%s%s", ss + 1, sss + 1);
memset(dp, -1, sizeof(dp));
prefun(sss);
preatm(sss);
dp[0][0] = 0;
int len2 = strlen(ss + 1);
for (int i = 1; ss[i]; ++i)
{
if (ss[i] == '?')
{
for (int j = 0; j < len; ++j)
{
if (dp[1 - i % 2][j] != -1)
{
for (int k = 0; k < 26; ++k)
{
dp[i % 2][prem[j][k]] = max(dp[1 - i % 2][j] + (prem[j][k] == len - 1), dp[i % 2][prem[j][k]]);
}
}
}
}
else
{
for (int j = 0; j < len; ++j)
{
if (dp[1 - i % 2][j] != -1)
{
dp[i % 2][prem[j][ss[i] - 'a']] = max(dp[1 - i % 2][j] + (prem[j][ss[i] - 'a'] == len - 1), dp[i % 2][prem[j][ss[i] - 'a']]);
}
}
}
for (int j = 0; j < len; ++j)
{
dp[1 - i % 2][j] = -1;
}
}
int ans = 0;
for (int i = 0; i < len; ++i)
{
ans = max(ans, dp[len2 % 2][i]);
}
printf("%d\n", ans);
return 0;
}

CodeForces 808G Anthem of Berland 前缀函数 KMP DP的更多相关文章

  1. codeforces 808G Anthem of Berland

    codeforces 808G Anthem of Berland 题面 给定\(s\)串和\(t\)串,字符集是小写字母.\(s\)串中有些位置的值不确定,要求你确定这些位置上的值,使得\(t\)在 ...

  2. Codeforces 808G Anthem of Berland - KMP - 动态规划

    题目传送门 传送点I 传送点II 传送点III 题目大意 给定一个字符串$s$,和一个字符串$t$,$t$只包含小写字母,$s$包含小写字母和通配符'?'.询问$t$可能在$s$中出现最多多少次. 原 ...

  3. Codeforces 808G Anthem of Berland【KMP】【DP】

    LINK 简要题意 给你一个串s,上面有字母和一些通配符,问你将通配符换成字母之后最多可以出现多少次串t 首先有一个很傻子的做法就是\(dp_{i,j}\)表示s到第i个位置匹配t串前j个字符的完整t ...

  4. Codeforces 808G Anthem of Berland(KMP+基础DP)

    题意 给定一个字符串 \(s\) ,一个字符串 \(t\) ,其中 \(s\) 包含小写字母和 "?" ,\(t\) 只包含小写字母,现在把 \(s\) 中的问号替换成任意的小写字 ...

  5. 2021.08.30 前缀函数和KMP

    2021.08.30 前缀函数和KMP KMP算法详解-彻底清楚了(转载+部分原创) - sofu6 - 博客园 (cnblogs.com) KMP算法next数组的一种理解思路 - 挠到头秃 - 博 ...

  6. 前缀函数与Z函数介绍

    字符串算法果然玄学=_= 参考资料: OI Wiki:前缀函数与KMP算法 OI Wiki:Z函数(扩展KMP) 0. 约定 字符串的下标从 \(0\) 开始.\(|s|\) 表示字符串 \(s\) ...

  7. 转载 - kmp next函数 kmp的周期问题,深入了解kmp中next的原理

    出处:http://www.cnblogs.com/wuyiqi/archive/2012/01/06/2314078.html kmp next函数 kmp的周期问题,深入了解kmp中next的原理 ...

  8. POJ 3336 Count the string (KMP+DP,好题)

    参考连接: KMP+DP: http://www.cnblogs.com/yuelingzhi/archive/2011/08/03/2126346.html 另外给出一个没用dp做的:http:// ...

  9. 【KMP+DP】Count the string

    KMP算法的综合练习 DP很久没写搞了半天才明白.本题结合Next[]的意义以及动态规划考察对KMP算法的掌握. Problem Description It is well known that A ...

  10. codeforces432D Prefixes and Suffixes(kmp+dp)

    转载请注明出处: http://www.cnblogs.com/fraud/          ——by fraud D. Prefixes and Suffixes You have a strin ...

随机推荐

  1. Chapter 6. Build Script Basics

    Chapter 6. Build Script Basics 6.1. Projects and tasks Everything in Gradle sits on top of two basic ...

  2. 计算机的数值转化与网络的IP地址分类与地址划分

    数值转换 数字系统由来 远古时代是没有数字系统非位置化数字系统: 罗马数字 (I-1.II-2.III-3.IV-4.V-5.VI-6.VII-7.VIII-8.IX-9.X-10) 位置话数字化系统 ...

  3. CentOS7调整分区大小

    前言 部署CentOS7的时候分配的动态扩充虚拟磁盘,共1T大小,在安装Centos时默认分区,系统仅给/分配50G,而大量空间都挂载到/home下,最近CentOS7使用中发现空间已不足够,所以就想 ...

  4. ELK7.x环境部署

    1.Elasticsearch (ES)配置: 部署配置ES,需要配置JDK环境,JDK是Java语言的软件开发工具包: 下载JAVA jdk源码包: wget https://mirrors.yan ...

  5. 游戏客户端开发中对MVC模式的思考

    话说在前头,我分析MVC模式是为了确定自己要做的独立游戏的结构出来,并不适用于大型商业游戏的开发. MVC模式的概述 关于MVC模式,Model用于存储数据,View层用于显示数据,Controlle ...

  6. 以太坊和比特币区块链的异同(一些QA)

    1.比特币区块链和以太坊区块链有何区别? 比特币区块链与以太坊在设计和功能上有显著的不同.下面是关于比特币的主要点: 没有智能合约功能(按照以太坊的定义):比特币是为了作为一个去中心化的数字货币而创建 ...

  7. 解决使用mitmprox抓包可以访问网页,但是使用python request 调用该网站接口报错问题

    可能有几种原因导致这种情况.以下是一些常见的问题和可能的解决方法: 证书验证问题: 当你使用mitmproxy抓包时,它通常会生成自签名的SSL证书,以便进行中间人攻击检查.但在Python中使用re ...

  8. 搓一个Pythonic list

      总所周知,Python语言当中的list是可以存储不同类型的元素的,对应到现代C++当中,可以用std::variant或者std::any实现类似的功能.而Python官方的实现当中用到了二级指 ...

  9. .Net8 Blazor 尝鲜

    全栈 Web UI 随着 .NET 8 的发布,Blazor 已成为全堆栈 Web UI 框架,可用于开发在组件或页面级别呈现内容的应用,其中包含: 用于生成静态 HTML 的静态服务器呈现. 使用 ...

  10. “技能兴鲁”职业技能大赛-网络安全赛项-学生组初赛 Crypto WP

    babyRSA 查看代码 from gmpy2 import * from Crypto.Util.number import * flag = 'flag{I\'m not gonna tell y ...