关于KMP的一点思考
关于KMP的一点思考
KMP的\(next\)数组的性质很精妙,有必要开一个坑学习一下
Part 1 啥是next
\(next[i]\)表示对于\(pre_i\)这个字符串,这个抠出来的字符串本身后缀和前缀相等的最长长度。是一个自变量只和这个子串有关的函数。这点很重要
由于保证了是最长长度,这个数有一些优良的性质,常常在关于一个串的循环表示或者周期表示中发挥作用。
注意到这个\(next[i]\)虽然代表是这个最长长度,但是值得注意的是,由于字符串从1开始编号,所以这个值也是那个前缀的下标。
Part2 如何求next
边界条件是,\(nx[1]=0\)。考虑我们若已经求得前面\(i-1\)的位置的\(nx\)值,现在如何求\(nx[i]\)。
把\(S[1\dots i-1]\)看做一个整体,现在我们在后面加入了一个字符\(S[i]=c\)。
我们现在就是要在\(pre_{nx[i-1]}\)中截一个最大的位置\(p\),使得\(S[p+1]=c\),而\(p\)虽然是下标,但是由于从\(1\)开始编号那么就同时就是这个串的长度,所以\(nx[i]=p+1\)。为什么是在\(pre_{nx[i-1]}\)中找呢?因为我们要保证\(S[i-p+1...i]=S[1,p]\)。
所以如何找\(p\)呢?由于我们要保证刚刚写的这个等式,可以发现\(p\)一定是在\(G=(V,E),E=(x,nx[x])\)这样的图中和\(nx[i-1]\)联通的到祖先的链上,所以我们一直暴力跳\(nx[]\)也就是遍历这条链,直到第一次找到一个位置\(p\)使得\(S[nx[p]+1]=S[i]\)。
但是你可能觉得这样的复杂度是假的,下面我将证(复)明(读)暴力跳\(nx[]\)遍历的复杂度不超过\(O(n)\)
可以发现\(nx[i]\le nx[i-1]+1\),得证。
哈哈哈哈
其实就是,\(nx[i]\)的总增长是\(O(n)\)的,而且一次最多增长\(1\),所以在其间不断跳的复杂度不超过\(O(n)\)。(总共只有这么多\(nx\)给你跳啊!)
代码:
for(int t=2;t<=s2;++t){
nx[t]=nx[t-1];
while(nx[t]>0&&T[nx[t]+1]!=T[t]) nx[t]=nx[nx[t]];
if(T[nx[t]+1]==T[t]) ++nx[t];
}
Part 3 一些性质
由于我马上就要咕咕咕所以
P3435 [POI2006]OKR-Periods of Words
//@winlere
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define getchar() (__c==__ed?(__ed=__buf+fread(__c=__buf,1,1<<18,stdin),*__c++):*__c++)
using namespace std; typedef long long ll; char __buf[1<<18],*__c=__buf,*__ed=__buf;
inline int qr(){
register int ret=0,f=0;
register char c=getchar();
while(!isdigit(c))f|=c==45,c=getchar();
while(isdigit(c)) ret=ret*10+c-48,c=getchar();
return f?-ret:ret;
}
const int maxn=1e6+5;
char c[maxn];
int n,nx[maxn],cut[maxn];
inline void kmp(){
for(int t=2;t<=n;++t){
nx[t]=nx[t-1];
while(nx[t]>0&&c[nx[t]+1]!=c[t]) nx[t]=nx[nx[t]];
if(c[nx[t]+1]==c[t]) ++nx[t];
}
}
int Find(const int&p){
if(!nx[p]) return p;
if(cut[p]) return cut[p];
return cut[p]=Find(nx[p]);
}
int main(){
#ifndef ONLINE_JUDGE
freopen("in.in","r",stdin);
//freopen("out.out","w",stdout);
#endif
scanf("%d%s",&n,c+1);
kmp();
ll ans=0;
for(int t=1;t<=n;++t)
ans=(ans+t-Find(t));
printf("%lld\n",ans);
return 0;
}
[P4824 USACO15FEB]Censoring (Silver) 审查(银)
//@winlere
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std; typedef long long ll;
const int maxn=1e6+5;
char S[maxn],T[maxn];
pair<int,int> stk[maxn];
int s1,s2,top,nx[maxn];
int main(){
#ifndef ONLINE_JUDGE
freopen("in.in","r",stdin);
freopen("out.out","w",stdout);
#endif
scanf("%s%s",S+1,T+1);
s1=strlen(S+1);
s2=strlen(T+1);
for(int t=2;t<=s2;++t){
nx[t]=nx[t-1];
while(nx[t]>0&&T[nx[t]+1]!=T[t]) nx[t]=nx[nx[t]];
if(T[nx[t]+1]==T[t]) ++nx[t];
}
int p=0;
for(int t=1;t<=s1;++t){
while(p&&T[p+1]!=S[t]) p=nx[p];
if(T[p+1]==S[t]) ++p;
stk[++top]=(pair<int,int>){t,p};
if(p==s2) top-=s2,p=stk[top].second;
}
for(int t=1;t<=top;++t) printf("%c",S[stk[t].first]);
putchar('\n');
return 0;
}
关于KMP的一点思考的更多相关文章
- 关于java异常的一点思考
关于异常的一点思考 异常生命周期 异常的来源 所有的异常都是抛出来的 有底层api抛出的 有自定义抛出的 异常的处理 1, 运行时异常 不做任何处理仍可编译通过 不建议捕获(不建议用异常来做流程控制, ...
- MSSQL显错注入爆数字型数据的一点思考
Title:MSSQL显错注入爆数字型数据的一点思考 --2011-02-22 15:23 MSSQL+ASP 最近在弄个站点,密码是纯数字的,convert(int,())转换出来不报错,也不知道其 ...
- 对dump脱壳的一点思考
对dump脱壳的一点思考 偶然翻了一下手机日历,原来今天是夏至啊,时间过的真快.ISCC的比赛已经持续了2个多月了,我也跟着比赛的那些题目学了2个月.......虽然过程很辛苦,但感觉还是很幸运的,能 ...
- 关于linux kernel slab内存管理的一点思考
linux kernel 内存管理是个很大的话题,这里记录一点个人关于slab模块的一点思考总结. 有些书把slab介绍成高速缓存,这会让人和cache,特别是cpu cache混淆,造成误解.sla ...
- 关于html页面元素语义化的一点思考
这几天在看招聘公告前端工程师的要求基本都附带了html语义化的要求,所以稍微关注了下这方面的知识.对于其中的一点就是要求页面元素在去除css样式之后还能有良好的布局引发了我一点思考.作为前端刚入门的我 ...
- c#Winform程序调用app.config文件配置数据库连接字符串 SQL Server文章目录 浅谈SQL Server中统计对于查询的影响 有关索引的DMV SQL Server中的执行引擎入门 【译】表变量和临时表的比较 对于表列数据类型选择的一点思考 SQL Server复制入门(一)----复制简介 操作系统中的进程与线程
c#Winform程序调用app.config文件配置数据库连接字符串 你新建winform项目的时候,会有一个app.config的配置文件,写在里面的<connectionStrings n ...
- 基于CAS分析对ABA问题的一点思考
基于CAS分析对ABA问题的一点思考 什么是CAS? 背景 synchronized加锁消耗太大 volatile只保证可见性,不保证原子性 基础 用CPU提供的特殊指令,可以: 自动更新共享数据; ...
- 【翻译】全球用尽IPv4的一点思考
作者:Dimple 公众号:奔跑吧攻城狮 简介:专属于Java和Android开发,和你聊聊职场话题,一同展望未来 作为小小号主的我表示很无力啊,这几天,天天都是热点.前有网易员工勇敢发声维护自己的利 ...
- [技术博客] 软工-Ruby on Rails前端工具链的配置以及对Web应用结构设计的一点思考
一.相关工具链简介 HAML HAML是专门面向Ruby on Rails模版语法设计的一门标记语言,其结合RoR的views部分模版语法的特点,对原来的*.html.erb(嵌入Ruby代码的HTM ...
随机推荐
- 03寻找最小的k个数
题目描述:查找最小的k个元素 题目:输入n个整数,输出其中最小的k个. 例如输入1,2,3,4,5,6,7和8这8个数字,则最小的4个数字为1,2,3和4. 1:最简单 ...
- 【tensorflow】】模型优化(一)指数衰减学习率
指数衰减学习率是先使用较大的学习率来快速得到一个较优的解,然后随着迭代的继续,逐步减小学习率,使得模型在训练后期更加稳定.在训练神经网络时,需要设置学习率(learning rate)控制参数的更新速 ...
- 用CSS画平行四边形
<div class="jx">我是一个平行四边形</div> <style> .jx{ //定义div的高度宽度 transform:skew ...
- C# TransactionScope 事务类
微软自带的TransactionScope(.Net Framework 2之后)是个好东东,提供的功能也很强大. 首先说说TransactionScope是什么,并能为我们做什么事情.其实看Tran ...
- C# 7.2 通过 in 和 readonly struct 减少方法值复制提高性能
在 C# 7.2 提供了一系列的方法用于方法参数传输的时候减少对结构体的复制从而可以高效使用内存同时提高性能 在开始阅读之前,希望读者对 C# 的值类型.引用类型有比较深刻的认知. 在 C# 中,如果 ...
- H3C H3C设备DNS功能实现
- 深度学习——CNN
整理自: https://blog.csdn.net/woaidapaopao/article/details/77806273?locationnum=9&fps=1 思想 filter尺寸 ...
- C# 字典 Dictionary 的 TryGetValue 与先判断 ContainsKey 然后 Get 的性能对比
本文使用 benchmarkdotnet 测试字典的性能,在使用字典获取一个可能存在的值的时候可以使用两个不同的写法,于是本文分析两个写法的性能. 判断值存在,如果值存在就获取值,可以使用下面两个不同 ...
- HDU - 5015 233 Matrix (矩阵快速幂)
In our daily life we often use 233 to express our feelings. Actually, we may say 2333, 23333, or 233 ...
- 思数云hadoop目录
全文检索.数据分析挖掘.推荐系统.广告系统.图像识别.海量存储.快速查询 l Hadoop介绍 n Hadoop来源与历史 n Hadoop版本 n Hadoop开源与商业 l HDFS系统架构 n ...