关于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的一点思考的更多相关文章

  1. 关于java异常的一点思考

    关于异常的一点思考 异常生命周期 异常的来源 所有的异常都是抛出来的 有底层api抛出的 有自定义抛出的 异常的处理 1, 运行时异常 不做任何处理仍可编译通过 不建议捕获(不建议用异常来做流程控制, ...

  2. MSSQL显错注入爆数字型数据的一点思考

    Title:MSSQL显错注入爆数字型数据的一点思考 --2011-02-22 15:23 MSSQL+ASP 最近在弄个站点,密码是纯数字的,convert(int,())转换出来不报错,也不知道其 ...

  3. 对dump脱壳的一点思考

    对dump脱壳的一点思考 偶然翻了一下手机日历,原来今天是夏至啊,时间过的真快.ISCC的比赛已经持续了2个多月了,我也跟着比赛的那些题目学了2个月.......虽然过程很辛苦,但感觉还是很幸运的,能 ...

  4. 关于linux kernel slab内存管理的一点思考

    linux kernel 内存管理是个很大的话题,这里记录一点个人关于slab模块的一点思考总结. 有些书把slab介绍成高速缓存,这会让人和cache,特别是cpu cache混淆,造成误解.sla ...

  5. 关于html页面元素语义化的一点思考

    这几天在看招聘公告前端工程师的要求基本都附带了html语义化的要求,所以稍微关注了下这方面的知识.对于其中的一点就是要求页面元素在去除css样式之后还能有良好的布局引发了我一点思考.作为前端刚入门的我 ...

  6. c#Winform程序调用app.config文件配置数据库连接字符串 SQL Server文章目录 浅谈SQL Server中统计对于查询的影响 有关索引的DMV SQL Server中的执行引擎入门 【译】表变量和临时表的比较 对于表列数据类型选择的一点思考 SQL Server复制入门(一)----复制简介 操作系统中的进程与线程

    c#Winform程序调用app.config文件配置数据库连接字符串 你新建winform项目的时候,会有一个app.config的配置文件,写在里面的<connectionStrings n ...

  7. 基于CAS分析对ABA问题的一点思考

    基于CAS分析对ABA问题的一点思考 什么是CAS? 背景 synchronized加锁消耗太大 volatile只保证可见性,不保证原子性 基础 用CPU提供的特殊指令,可以: 自动更新共享数据; ...

  8. 【翻译】全球用尽IPv4的一点思考

    作者:Dimple 公众号:奔跑吧攻城狮 简介:专属于Java和Android开发,和你聊聊职场话题,一同展望未来 作为小小号主的我表示很无力啊,这几天,天天都是热点.前有网易员工勇敢发声维护自己的利 ...

  9. [技术博客] 软工-Ruby on Rails前端工具链的配置以及对Web应用结构设计的一点思考

    一.相关工具链简介 HAML HAML是专门面向Ruby on Rails模版语法设计的一门标记语言,其结合RoR的views部分模版语法的特点,对原来的*.html.erb(嵌入Ruby代码的HTM ...

随机推荐

  1. Hbase数据模型概念视图

  2. oracle多个平等的索引

    当SQL语句的执行路径可以使用分布在多个表上的多个索引时, ORACLE会同时使用多个索引并在运行时对它们的记录进行合并, 检索出仅对全部索引有效的记录. 在ORACLE选择执行路径时,唯一性索引的等 ...

  3. hdu 2986 Ballot evaluation (Simulation)

    Problem - 2986 之前在华工赛见过的一道简单的模拟,用map轻松干掉.为了精确,要全程用整型比较.轻松1y~ 代码如下: #include <cstdio> #include ...

  4. Python--day62--删除出版社

    删除成出版社关键代码:

  5. Nuget 通过 dotnet 命令行发布

    在开发完成一个好用的轮子就想将这个轮子发布到 nuget 让其他小伙伴可以来使用,但是 nuget.org 的登陆速度太慢,本文介绍一个命令行发布的方法,通过命令行发布的方法可以配合 Jenkins ...

  6. laravel怎么开启调试模式

      在.env文件里有个APP_DEBUG=true,如果是false,改成true就好了.

  7. .net连接数据库

    /* 连接数据库步骤-- 1.创建连接字符串 data source = ... 计算机名称 initial catalog = ... 数据库名称 integrated security = tru ...

  8. 2018-8-10-win10-uwp-x_Bind-无法获得资源

    title author date CreateTime categories win10 uwp x:Bind 无法获得资源 lindexi 2018-08-10 19:17:19 +0800 20 ...

  9. H3C DHCP中继配置示例

  10. linux 基于 jiffy 的超时

    到目前为止所展示的次优化的延时循环通过查看 jiffy 计数器而不告诉任何人来工作. 但是最好的实现一个延时的方法, 如你可能猜想的, 常常是请求内核为你做. 有 2 种方 法来建立一个基于 jiff ...