LG2375/LOJ2246 「NOI2014」动物园 KMP改造
2024-09-06 09:48:40
问题描述
题解
看了题解,需要回看,需要继续通过本题深入理解KMP。
为了将 \(\mathrm{KMP}\) 和只插入了一个模式串的\(\mathrm{AC}\)自动机有机统一,称通常意义下的 \(\mathrm{KMP}\) 的 \(\mathrm{next}\) 数组为 \(\mathrm{fail}\) 。
通过对 \(\mathrm{num}\) 数组的观察,发现, \(\mathrm{num}\) 数组就是对于每一个前缀,求其公共不重叠前后缀的个数。
由于只有一个串,通过 \(L \le 10^6\) 的线性复杂度的数据规模,可以猜出肯定和 \(\mathrm{KMP}\) 有关。
回顾 \(\mathrm{KMP}\) 中 \(\mathrm{fail}\) 数组的定义,是对于每一个前缀,其 最长公共前后缀的长度 。
对于一个前缀 \(i\) ,\(fail[i]\) 是它的一个公共前后缀,那么 \(fail[fail[i]]\) 也是它的公共前后缀。
可以画图来理解一下:
同理, \(fail[fail[fail[i]]]\) ... 都是前缀 \(i\) 的公共前后缀。
于是通过这个办法递推一下前缀 \(i\) 的公共前后缀数目(允许重叠),这实际上就是 \(\mathrm{num}\) 数组的弱化版,即允许重叠的版本。
实际上,我们求出的这个弱化版数组,就是比实际上的 \(num\) 数组长了一点,所以做第二次 \(\mathrm{KMP}\) 的时候,只需要再让 \(j\) 跳 \(\mathrm{fail}\) ,直到它的一半比 \(i\) 小。
为什么是一半?显然 \(num_i \le \frac{i}{2}\) 。
\(\mathrm{Code}\)
#include<bits/stdc++.h>
using namespace std;
template <typename Tp>
void read(Tp &x){
x=0;char ch=1;int fh;
while(ch!='-'&&(ch>'9'||ch<'0')) ch=getchar();
if(ch=='-') ch=getchar(),fh=-1;
else fh=1;
while(ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
x*=fh;
}
const int maxn=1000000+7;
const int mod=1000000007;
int T,n;
char s[maxn];
int fail[maxn],num[maxn];
void Reset(){
memset(fail,0,sizeof(fail));
}
void KMP(){
num[1]=1;
for(int i=2,j=0;i<=n;i++){
while(j&&s[j+1]!=s[i]) j=fail[j];
if(s[j+1]==s[i]) ++j;
fail[i]=j;num[i]=num[j]+1;
}
}
void solve(){
KMP();
long long ans=1;
for(int i=2,j=0;i<=n;i++){
while(j&&s[i]!=s[j+1]) j=fail[j];
if(s[i]==s[j+1]) ++j;
while((j<<1)>i) j=fail[j];
ans=ans*(((long long)num[j]+1ll)%mod)%mod;
}
printf("%lld\n",ans);
}
int main(){
read(T);
while(T--){
scanf("%s",s+1);n=strlen(s+1);
solve();
}
return 0;
}
最新文章
- [C#] 走进异步编程的世界 - 在 GUI 中执行异步操作
- 十一个行为模式之策略模式(Strategy Pattern)
- Android手机截屏
- 【英语】Bingo口语笔记(32) - 口语中的弱读
- Ubuntu解决Sublime Text 2安装GBK Encoding Support插件仍然乱码
- 基于css3新属性transform及原生js实现鼠标拖动3d立方体旋转
- Android WebView挂马漏洞--各大厂商纷纷落马
- Python全栈之路-Day31
- 特征提取算法的综合实验(多种角度比较sift/surf/brisk/orb/akze)
- ClearCase新增文件
- Hibernate查询之SQL查询,查询结果用new新对象的方式接受,hql查询,通过SQL查询的结果返回到一个实体中,查询不同表中内容,并将查到的不同表中的内容放到List中
- mysql关于排序值的问题,指定排序值
- ubuntu16系统中pycharm下使用git将代码提交到github仓库
- transiton,transform,animation,border-image
- Template literals
- Javascript系列:总体理解
- Django之模型系统
- API密钥
- RTX——第16章 消息邮箱
- c语言中函数参数入栈的顺序是什么?为什么
热门文章
- 新手springmvc web简单搭建过程-caidachun
- GAN网络原理介绍和代码
- BZOJ2339/LG3214 「HNOI2011」 卡农 组合数学
- python集合、元组、字典
- php获取url中的参数
- 【转】Ubuntu 16 安装 python 依赖出现 error: command &#39;i686-linux-gnu-gcc&#39; failed with exit status 1
- c#中list集合使用Max()方法查找到最大值
- File获取当前目录下的所有子项 listFiles()
- CSS3 新增选择器
- [b0006] Spark 2.0.1 伪分布式搭建练手