(我和lesphere,reverse研究了这个东西一上午)QAQ

kmp是求字符串S的任意前缀与字符串T的最长的相同的前缀和后缀

exkmp第求字符串S的任意后缀与字符串T的最长公共前缀

与kmp相同,我们先来看S与S自己匹配,也就是求S得任意后缀与S的最长公共前缀pre[]数组

假设我们已经得到了k之前的所有答案:pre[0~k-1]   和   k之前使得i+pre[i]最大的点a(也就是能够延伸到最远的点)

如果a+pre[a]-1(延伸最远的位置)<k(不包含k)那么就暴力往后找就对了

如图是当a+pre[a]-1能包含k的情况:

显然s[0~pre[a]-1]==s[a~a+pre[a]-1]两个矩形是完全相同的(并且s[pre[a]+1]!=s[a+pre[a]]);

而且k在前面矩形中对应点k-a

那么现在有三种情况:

(1):pre[k-a]+k-a-1<pre[a]-1;

  也就是说k-a延伸出去也不会超过pre[a]-1的矩形右边界假设l=pre[k-a];

  换句话说就是s[l]!=s[k-a+l];

  又因为两个矩形完全相同,所以pre[k]不会再在s[k+l]之后匹配上(延伸),所以pre[k]=l=pre[k-a];直接赋值就好;

(2):pre[k-a]+k-a-1>pre[a]-1;

  与情况1相反,l=pre[k-a]延伸出了矩形右边框:

  如图,两个矩形右边框的右边的那个点不同(s[pre[a]+1]!=s[a+pre[a]]);

  又因为左边两个l完全相同,所以s[pre[a]+1]==s[pre[a]-(k-a)](图中左边上面箭头(标有相同))

  所以右边矩形后面第一个点s[p+1]!=s[pre[a]-(k-a)],所以pre[k]必定等于l在矩形中的部分长度,所以直接赋值就好;

(3):pre[k-a]+k-a-1==pre[a]-1;

  也就是说pre[k-a]刚好等于左边矩形右边框;

  如图,由于s[pre[i]+i]!=s[pre[i]]的限制,导致两个不同,而下面的箭头就不能确定了;

  于是我们对于这样的情况,就只有从右矩形边框暴力往后找了;

这样所有情况就讨论完了,递推即可

下面给出代码:

 void getpre(char *s)
{
int len=strlen(s),a=;
pre[]=len;
while(a<len-&&s[a]==s[a+])a++;
pre[]=a;
a=;
re(k,,len-)
{
int p=a+pre[a]-,l=pre[k-a];
if(k-+l>=p)
{
int j=(p-k+)>?(p-k+):;
while(k+j<len&&s[k+j]==s[j])j++;
pre[k]=j;
a=k;
}
else pre[k]=l;
}
}

S与自身的匹配和S与T的匹配类似,下面给出代码:

 void getextend(char *s,char *t)
{
int n=strlen(s),m=strlen(t),a=;
getpre(s);
while(a<n-&&s[a]==t[a+])a++;
Max[]=a;
a=;
re(k,,n-)
{
int p=a+Max[a]-,l=pre[k-a];
if(k+l->=p)
{
int j=(p-k+)>?(p-k+):;
while(k+j<m&&s[k+j]==t[j])j++;
Max[k]=j;
a=k;
}
else Max[k]=l;
}
}

是不是感觉差不多……

附上lesphere%%%代码:

 void getfail(){
fail[]=m;
while(fail[]<n && a[fail[]]==a[fail[]+]) fail[]++;
for(int i=,j=,mx=+fail[];i<n;i++){
if(mx-<i || mx-i==fail[i-j]){
if(i<=mx-) fail[i]=fail[i-j];
while(fail[i]<n && a[fail[i]]==a[fail[i]+i]) fail[i]++;
}
else fail[i]=min(mx-i,fail[i-j]);
if(mx<i+fail[i]) j=i,mx=i+fail[i];
}
}
void getex(){
getfail();
while(ex[]<n && a[ex[]]==b[ex[]]) ex[]++;
for(int i=,j=,mx=ex[];i<n;i++){
if(mx-<i || mx-i==fail[i-j]){
if(i<=mx-) ex[i]=fail[i-j];
while(ex[i]<n && a[ex[i]]==b[ex[i]+i]) ex[i]++;
}
else ex[i]=min(mx-i,fail[i-j]);
if(mx<i+ex[i]) j=i,mx=i+ex[i];
}
}

EXKMP的更多相关文章

  1. Revolving Digits[EXKMP]

    Revolving Digits Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) ...

  2. 【无聊放个模板系列】POJ2752 EXKMP

    #include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #inc ...

  3. BNUOJ34990--Justice String (exkmp求最长公共前缀)

    Justice String Given two strings A and B, your task is to find a substring of A called justice strin ...

  4. ExKMP(Z Algorithm) 讲解

    目录 问题引入 CaiOJ 1461 [EXKMP]最长共同前缀长度 算法讲解 匹配过程 next 的求解 复杂度证明 代码解决 一些例题 UOJ #5. [NOI2014]动物园 CF1051E V ...

  5. CodeForces1051E EXKMP + 线段树dp

    http://codeforces.com/problemset/problem/1051/E 题意:给你一个很大的数字,然后你可以把这个数字拆分成为任意多个部分,要求每一个部分的数字大小要在一个区间 ...

  6. HDU3613 Manacher//EXKMP//KMP

    http://acm.hdu.edu.cn/showproblem.php?pid=3613 每个字符都有一个权值,将一个字符串分成两半,如果某一半是回文串就把所有的字符权值加起来,否则当0来处理,问 ...

  7. poj3376 Finding Palindromes【exKMP】【Trie】

    Finding Palindromes Time Limit: 10000MS   Memory Limit: 262144K Total Submissions:4710   Accepted: 8 ...

  8. hdu3374 String Problem【最小表示法】【exKMP】

    String Problem Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)To ...

  9. 2018ACM-ICPC南京区域赛M---Mediocre String Problem【exKMP】【Manacher】

    这题就单独写个题解吧.想了两天了,刚刚问了一个大佬思路基本上有了. 题意: 一个串$S$,一个串$T$,在$S$中选一段子串$S[i,j]$,在$T$中选一段前缀$T[1,k]$使得$S[i,j]T[ ...

随机推荐

  1. Spark2 Dataset多维度统计cube与rollup

    val df6 = spark.sql("select gender,children,max(age),avg(age),count(age) from Affairs group by ...

  2. Spark2 broadcast广播变量

    A broadcast variable. Broadcast variables allow the programmer to keep a read-only variable cached o ...

  3. 伪随机数生成算法-梅森旋转(Mersenne Twister/MT)

    今天主要是来研究梅森旋转算法,它是用来产生伪随机数的,实际上产生伪随机数的方法有很多种,比如线性同余法, 平方取中法等等.但是这些方法产生的随机数质量往往不是很高,而今天介绍的梅森旋转算法可以产生高质 ...

  4. 使用keras导入densenet模型

    从keras的keras_applications的文件夹内可以找到内置模型的源代码 Kera的应用模块Application提供了带有预训练权重的Keras模型,这些模型可以用来进行预测.特征提取和 ...

  5. opencv学习笔记——时间计算函数getTickCount()和getTickFrequency()

    cv::getTickCount()可以用来测量一段代码的运行时间,这个函数返回从上次开机算起的时钟周期数. 由于我们需要的是某个代码段运行的毫秒数,因此还需要另一个函数cv::getTickFreq ...

  6. easyui 特殊操作

    --EasyUI - datagrid中单元格里编辑控件的单击事件如何获取当前行的index var rowIndex = $(this).parents('.datagrid-row').attr( ...

  7. ubuntu 添加用户到已存在的组

    sudo adduser 用户名 组名   sudo minicom –s 配置 minicom访问ttyUSB0没权限,发现属于dialout 组 james@james-OptiPlex-380: ...

  8. Bone Collector--hdu2602(01背包)

    Problem Description Many years ago , in Teddy’s hometown there was a man who was called “Bone Collec ...

  9. php 中date显示时间不对与Linux文件乱码问题

    php 中date显示时间不对解决办法如下1.修改/etc/php.ini文件 在里头中找到data.timezone =去掉它前面的分号';' 然后设置data.timezone = “Asia/S ...

  10. HIVE表保存的路径

    HIVE表保存的默认路径在${HIVE_HOME}/conf/hive-site.xml配置文件的hive.metastore.warehouse.dir属性指定