P8112 [Cnoi2021]符文破译

借用 KMP 思想优化的动态规划。

首先,用 \(dp[i]\) 表示把前 \(i\) 位的字符完全匹配需要的最少词缀数(下标均从 \(1\) 开始)。那么,我们可以从点 \(i+1\) 开始,向后逐位与字符串 \(T\) 比较。设此时匹配到了 \(T\) 中的第 \(j\) 位,如果相等,则易得转移方程:

\[dp[i+j]=\min(dp[i+j],dp[i]+1)
\]

如果不相等或到达了字符串 \(T\) 末尾,则证明在此之后不会更长的有魔法词缀,可以结束这一次匹配,令 \(i=i+1\) 计算下一位即可。

很明显,这个算法的时间复杂度是 \(O(|S||T|)\) 的,当数据范围达到 \(|S|,|T|\le10^6\) 时,算法必然超时。

考虑优化这个算法,我们知道,如果不相等或到达了字符串 \(T\) 末尾,失配后是可以直接跳过一部分不可能产生新的解的数据。这样就自然而然地想到了用这个思想把单模字符串匹配优化到 \(O(|S|+|T|)\) 的 KMP 算法。

借助 KMP 的思想,首先求出字符串 \(T\) 的 \(next\) 数组,然后开始按照 KMP 的方式匹配:(设此时文本串匹配到第 \(i\) 项,模式串匹配到第 \(j\) 项)

设置一个名为 \(now\) 的临时变量,用于存储如果匹配的最少词缀数。

可以直接逐位比较。如果相等,则按照 KMP 思想,将模式串和文本串指针一起后移,令 \(dp[i]=now\) 后比较下一位。

如果不相等,可以令 \(j=next[j]\) 之后重新计算 \(now\) 的值。因为一旦匹配失败,只能再次选择一个词缀。每次 KMP 算法在匹配失败后,会利用最长公共前后缀的性质使得文本串指针 \(i\) 不往前跳。而每次利用最长公共前后缀的性质,会改变模式串匹配的起始位置,所以需要重新计算 \(now\) 的值。可以直接用 \(dp[i-j]\) 计算出模式串匹配的起始位置的前一个位置,把 \(now\) 的值更新为 \(dp[i-j]+1\) 以保证正确性。模式串匹配到末尾也是同理。

DP 边界:\(dp[0]=1\)。

DP 目标:\(dp[|S|]\)。

时间复杂度:\(O(|S|+|T|)\)。

注意,由于有无解的情况,所以当 \(next\) 数组跳到 \(-1\) 时,应该直接判定无解并输出 Fake。因为如果 \(next\) 数组跳到 \(-1\) 证明匹配第一个字符就失配了,此时后面没有办法再进行匹配,无解。

完整代码:(由于代码中的字符串下标是从 \(0\) 开始的,所以可能会和上文的讲解有些出入)

#include <bits/stdc++.h>
using namespace std;
int lt,ls,next1[10000010],f[10000010];
char t[10000010],s[10000010];
void get_next(char t[],int next[])
{
int i=0,j=-1;
next[0]=-1;
while(i<lt)
{
if(j==-1||t[i]==t[j])i++,j++,next[i]=j;
else j=next[j];
}
} bool kmp(char s[],char t[],int next[])
{
int i=0,j=0,now=1;
f[0]=1;
while(i<ls)
{
if(j==-1)return 0;
if(s[i]==t[j])i++,j++,f[i]=now;
else j=next[j],now=f[i-j]+1;
if(j==lt)now=f[i-j]+1,j=next[j];
}
return 1;
} int main()
{
scanf("%d%d%s%s",&lt,&ls,t,s);
get_next(t,next1);
if(!kmp(s,t,next1))printf("Fake");
else printf("%d",f[ls]);
return 0;
}

AC记录

Luogu P8112 [Cnoi2021]符文破译 题解的更多相关文章

  1. luogu P1126 机器人搬重物 题解

    luogu P1126 机器人搬重物 题解 题目描述 机器人移动学会(\(RMI\))现在正尝试用机器人搬运物品.机器人的形状是一个直径\(1.6\)米的球.在试验阶段,机器人被用于在一个储藏室中搬运 ...

  2. P8112 符文破译

    题目描述 将字符串 \(T\) 拆成若干个子串,使这些子串为字符串 \(S\) 的前缀,要求拆分形成的子串数最小. 思路整理 实际上并不需要倒着枚举,也不需要线段树,更不需要 Z 函数. 如果你做过 ...

  3. 【luogu P2491 [SDOI2011]消防】 题解

    题目链接:https://www.luogu.org/problemnew/show/P2491 题外话: OI一共只有三种题--会的题,不会的题,二分题. 题解: step 1 求树的直径,把树的直 ...

  4. 【luogu P1040 加分二叉树】 题解

    题目链接:https://www.luogu.org/problemnew/show/P1040 今天考试考了一个区间DP...没错就是这个... 太蒟了真是连区间DP都不会...看了看题解也看不懂, ...

  5. Luogu P1351 联合权值 题解

    这是一个不错的树形结构的题,由于本蒟蒻不会推什么神奇的公式其实是懒得推...,所以很愉快的发现其实只需要两个点之间的关系为祖父和儿子.或者是兄弟即可. 然后问题就变得很简单了,只需要做一个正常的DFS ...

  6. 【luogu P1850 换教室】 题解

    题目链接:https://www.luogu.org/problemnew/show/P1850 难的不在状态上,难在转移方程. (话说方程写错居然还有84分= =) #include <cst ...

  7. 【luogu P1558 色板游戏】 题解

    题目链接:https://www.luogu.org/problemnew/show/P1558 我知道三十棵线段树很暴力,可是我们可以状压啊. 颜色最多30,不会爆int 另外 吐槽评测机 #inc ...

  8. 【luogu P3953 逛公园】 题解

    题目链接:https://www.luogu.org/problemnew/show/P3953 题外话:感觉2017年神题好多..这还不是最神的一道,真在考场上我也就写个最短路计数暴力了.现在在大佬 ...

  9. 【luogu P1608 路径统计】 题解

    题目链接:https://www.luogu.org/problemnew/show/P1608 补上一发最短路计数! 感谢王强qwqqqq @Lance1ot #include <queue& ...

  10. 【luogu P1156 垃圾陷阱】 题解

    题目链接:https://www.luogu.org/problemnew/show/P1156 设\(dp[i][j]\)表示前i堆到达高度j时的所活最长时间 那么一旦到当前状态能到达满足的时间和高 ...

随机推荐

  1. ReentrantLock底层源码分析

    一.简单使用 在聊它的源码之前,我们先来做个简单的使用说明.当我在IDEA中创建了一个简单的Demo之后,它会给出以下提示 提示文字 在使用阻塞等待获取锁的方式中,必须在try代码块之外,并且在加锁方 ...

  2. redis的作用:高性能和高并发

    一.高性能 假设这么个场景,你有个操作,一个请求过来,吭哧吭哧你各种乱七八糟操作mysql,半天查出来一个结果,耗时600ms.但是这个结果可能接下来几个小时都不会变了,或者变了也可以不用立即反馈给用 ...

  3. 为啥有好多人说 Arduino 是玩具?

    作为一个在嵌入式领域摸爬滚打近十年的老兵,我不得不说这个问题触动了我的神经.每次听到有人说"Arduino只是个玩具",我都忍不住想反驳,但冷静下来思考后,我发现这个问题并不是非黑 ...

  4. python调用QQ机器人向指定QQ发消息

    暂时没想到这个能用来干什么,只是刚好看到相关文章,学习一下,就拿获取基金信息来做试验把 爬取基金的信息就不介绍了,请参考https://www.cnblogs.com/becks/p/14500495 ...

  5. 在WampServer下增加PHP版本

    WampServer更新比较慢,需要新版本的php时就需要我们自己去添加了. 步骤(这里默认你已经安装好了wampserver): 下载解压: 增加配置文件 重启wampserver 去php官网根据 ...

  6. .net core项目代码提交忽略文件.gitignore的配置

    根据语言自动生成 1. 访问 .gitignore.io 首先,访问 https://www.gitignore.io/.这是一个非常有用的网站,可以根据你的开发环境自动生成 .gitignore 文 ...

  7. GitLab——重置(reset)和还原(revert)

    Git 命令 reset 和 revert 的区别 - 知乎 (zhihu.com) 总结: git reset --hard 9201d9b19dbf5b4ceaf90f92fd4e4019b685 ...

  8. ESP32S3 BLE_HID的编程实现

    ESP32S3 BLE_HID的编程实现 BLE是低功耗蓝牙,HID是Human Interface Device,也就是人机接口设备. 主要用于无线连接并传输用户输入数据(如按键.触控.手势等). ...

  9. vue3 基础-slot 插槽

    前几篇的内容都是父子组件通过属性传值或者事件传值这样的. 本篇来学习父组件在调用子组件时, 如果想要给子组件传递特定的内容 (dom) , 则可通过 slot 这个设计来轻易实现哦. 例如现在有这样一 ...

  10. Python模块的搜索路径

    在Python中,模块搜索路径是指解释器用来查找导入模块的位置列表.了解和掌握Python模块搜索路径对于正确导入模块和管理模块的位置至关重要. Python模块搜索路径的主要来源包括当前目录.Pyt ...