Luogu P8112 [Cnoi2021]符文破译 题解
借用 KMP 思想优化的动态规划。
首先,用 \(dp[i]\) 表示把前 \(i\) 位的字符完全匹配需要的最少词缀数(下标均从 \(1\) 开始)。那么,我们可以从点 \(i+1\) 开始,向后逐位与字符串 \(T\) 比较。设此时匹配到了 \(T\) 中的第 \(j\) 位,如果相等,则易得转移方程:
\]
如果不相等或到达了字符串 \(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",<,&ls,t,s);
get_next(t,next1);
if(!kmp(s,t,next1))printf("Fake");
else printf("%d",f[ls]);
return 0;
}
Luogu P8112 [Cnoi2021]符文破译 题解的更多相关文章
- luogu P1126 机器人搬重物 题解
luogu P1126 机器人搬重物 题解 题目描述 机器人移动学会(\(RMI\))现在正尝试用机器人搬运物品.机器人的形状是一个直径\(1.6\)米的球.在试验阶段,机器人被用于在一个储藏室中搬运 ...
- P8112 符文破译
题目描述 将字符串 \(T\) 拆成若干个子串,使这些子串为字符串 \(S\) 的前缀,要求拆分形成的子串数最小. 思路整理 实际上并不需要倒着枚举,也不需要线段树,更不需要 Z 函数. 如果你做过 ...
- 【luogu P2491 [SDOI2011]消防】 题解
题目链接:https://www.luogu.org/problemnew/show/P2491 题外话: OI一共只有三种题--会的题,不会的题,二分题. 题解: step 1 求树的直径,把树的直 ...
- 【luogu P1040 加分二叉树】 题解
题目链接:https://www.luogu.org/problemnew/show/P1040 今天考试考了一个区间DP...没错就是这个... 太蒟了真是连区间DP都不会...看了看题解也看不懂, ...
- Luogu P1351 联合权值 题解
这是一个不错的树形结构的题,由于本蒟蒻不会推什么神奇的公式其实是懒得推...,所以很愉快的发现其实只需要两个点之间的关系为祖父和儿子.或者是兄弟即可. 然后问题就变得很简单了,只需要做一个正常的DFS ...
- 【luogu P1850 换教室】 题解
题目链接:https://www.luogu.org/problemnew/show/P1850 难的不在状态上,难在转移方程. (话说方程写错居然还有84分= =) #include <cst ...
- 【luogu P1558 色板游戏】 题解
题目链接:https://www.luogu.org/problemnew/show/P1558 我知道三十棵线段树很暴力,可是我们可以状压啊. 颜色最多30,不会爆int 另外 吐槽评测机 #inc ...
- 【luogu P3953 逛公园】 题解
题目链接:https://www.luogu.org/problemnew/show/P3953 题外话:感觉2017年神题好多..这还不是最神的一道,真在考场上我也就写个最短路计数暴力了.现在在大佬 ...
- 【luogu P1608 路径统计】 题解
题目链接:https://www.luogu.org/problemnew/show/P1608 补上一发最短路计数! 感谢王强qwqqqq @Lance1ot #include <queue& ...
- 【luogu P1156 垃圾陷阱】 题解
题目链接:https://www.luogu.org/problemnew/show/P1156 设\(dp[i][j]\)表示前i堆到达高度j时的所活最长时间 那么一旦到当前状态能到达满足的时间和高 ...
随机推荐
- 掌握Tortoise-ORM高级异步查询技巧
title: 掌握Tortoise-ORM高级异步查询技巧 date: 2025/04/22 12:05:33 updated: 2025/04/22 12:05:33 author: cmdrago ...
- CF1774C题解
题目传送门 假设最后一场的环境为 111,即温度大的人赢,那么温度为 111 的人即使活到了最后一场也必输. 同理,如果最后 kkk 场的环境都为 111,那么有 k(1∼k)k(1\sim k)k( ...
- Cline技术分析:prompt如何驱动大模型对本地文件实现自主变更
prompt如何驱动大模型对本地文件实现自主变更 在AI技术快速发展的今天,编程方式正在经历一场革命性的变革.从传统的"人写代码"到"AI辅助编程",再到&qu ...
- C#网络编程(二)----网络层/链路层
网络层协议 网络层(Network Layer) 的主要功能是实现主机之间的逻辑寻址.路由选择和分组转发,确保数据在不同网络(如局域网.广域网)之间的传输 协议类别 核心协议 路由协议 辅助协议 扩展 ...
- SQL Server 2025 中的改进
SQL Server 2025 中的改进 当我们接近 SQL Server 2025 的首次公开版本时,开始深入探究 Azure SQL DB 如今(已公布和未公布)但在 SQL Server 盒装产 ...
- xl2411p 显示器分辨率问题 IPS\TN
本来是想玩游戏来着,后来也没能玩起: 留下了个显示器明基xl2411p,昨天扒出来用起来吧. 玩游戏没毛病的,毕竟都是图片不存在文字的渲染问题,日常办公用起来就难受了,TN屏真是难受的了. 本来24寸 ...
- 凯撒密码--java实现
关于凯撒密码的介绍我就不多说了,感兴趣的可以看什么是凯撒密码?,我主要说的是java如何实现. 我发现网上有写java加密解密的,写的时候发现只需要一个转换函数就可以了,可以作为加密用,也可以用作解密 ...
- Python模块的搜索路径
在Python中,模块搜索路径是指解释器用来查找导入模块的位置列表.了解和掌握Python模块搜索路径对于正确导入模块和管理模块的位置至关重要. Python模块搜索路径的主要来源包括当前目录.Pyt ...
- python中的stub文件(.pyi)的用途
在阅读TVM源码时,发现了*.pyi文件,里面的函数没有具体的实现,都诸如如下的形式,感到很疑惑. @overload def getattr(__o: object, __name: str, __ ...
- Scipy中的稀疏矩阵的编码方式
import numpy as np from scipy import sparse (1)COO( Coordinate) 最直观的就是COO格式.它用了1维的数组来表示2维的矩阵,每个数组的长度 ...