关于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. HDU-1069_Monkey and Banana

    Monkey and Banana Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) P ...

  2. python 检测目录

    #!/usr/bin/env python# -*- coding:utf-8 -*-import osimport win32fileimport win32con ACTIONS = { 1 : ...

  3. C++:只用初始化列表初始化变量的几种情况

    1.类成员函数中const变量的初始化(也就是第一点) 有几个容易混淆的地方: (1)const 的变量只能通过构造函数的初始化列表进行初始化:(貌似在C++11中可以正常编译) (2)static ...

  4. ORACLE学习笔记-ORACLE(基本命令)

    --查看VGA信息: show sga; select * from v$sgastat;--可以通过以下几个动态性能视图查看信息: V$sysstat                系统统计信息 V ...

  5. E - D Tree HDU - 4812 点分治+逆元

    这道题非常巧妙!!! 我们进行点分治的时候,算出当前子节点的所有子树中的节点,到当前节点节点的儿子节点的距离,如下图意思就是 当前节点的红色节点,我们要求出红色节点的儿子节点绿色节点,所有绿色的子树节 ...

  6. SuperSocket命令程序集定义

    是的,SuperSocket是用反射来查找哪些公开的类实现了基本的命令接口,但是它只在你的AppServer类定义的程序集中查找. 举例来说, 你的 AppServer 定义在程序集 GameServ ...

  7. Scoop 包管理工具 安装

    本人浏览器已经跨域 https://get.scoop.sh 访问该地址成功 安装前提(所需要的环境): 操作环境:win10. 确保你的 PowerShell 版本 >= 3. win7或许低 ...

  8. torch.nn.LSTM()函数维度详解

    123456789101112lstm=nn.LSTM(input_size,                     hidden_size,                      num_la ...

  9. H3C 环路避免机制四:定义最大值

  10. H3C H3C设备DNS功能实现