(我和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];
}
}