扩展KMP求的是对于原串S1的每一个后缀子串与模式串S2的最长公共前缀
对KMP算法进行了优化,下面是模板
int Next[maxn],extend[maxn];
char s[1000050],t[1000050];
void getNext(char* str){
int i=0,j,pos,len=strlen(str);
Next[0]=len;
while(str[i]==str[i+1]&&i+1<len)i++;Next[1]=i;
pos=1;
for(int i=2;i<len;i++){
if(Next[i-pos]+i<Next[pos]+pos){
Next[i]=Next[i-pos];
}
else{
j=Next[pos]+pos-i;
if(j<0)j=0;//如果i比最远的的小,说明得从头开始。
while(i+j<len&&str[j]==str[j+i])j++;Next[i]=j;
pos=i;
}
}
}
void Exkmp(char* s,char* t){
int i=0,j,pos,l1=strlen(s),l2=strlen(t);
getNext(t);
while(s[i]==t[i]&&i<l1&&i<l2)i++;extend[0]=i;
pos=0;
for(int i=1;i<l1;i++){
if(Next[i-pos]+i<extend[pos]+pos)
extend[i]=Next[i-pos];
else{
j=extend[pos]+pos-i;
if(j<0)j=0;
while(i+j<l1&&j<l2&&s[i+j]==t[j])j++;extend[i]=j;
pos=i;
}
}
}
对于string matching这道题,直接套模板然后将str和自己做ekmp,最后将extend数组的数字加起来就可以得到答案
(注意要long long)
下面是ac代码
#include<stdio.h>
#include<string.h>
const int maxn = 1000005; //字符串长度最大值
long long next[maxn], ex[maxn]; //ex数组即为extend数组
char s[maxn];
//预处理计算next数组
void GETNEXT(char *str)
{
int i = 0, j, po, len = strlen(str);
next[0] = len; //初始化next[0],因为从0开头就可以匹配整个T,故为len /*与EXKMP代码不同处:无这句话*/
while(str[i] == str[i + 1] && i + 1 < len) //计算next[1] /*与EXKMP代码不同处:比较s1和s2*/
i++;
next[1] = i;/*与EXKMP代码不同处:ex[0]=i*/
po = 1; //初始化po的位置 /*与EXKMP代码不同处:po = 0*/
for(i = 2; i < len; i++)/*与EXKMP代码不同处:i从1开始*/
{
if(next[i - po] + i < next[po] + po) //第一种情况,可以直接得到next[i]的值 /*与EXKMP代码不同处:next[i-po]+i<ex[po]+po*/
next[i] = next[i - po];/*与EXKMP代码不同处:ex[i]=next[i-po];*/
else//第二种情况,要继续匹配才能得到next[i]的值
{
j = next[po] + po - i;/*与EXKMP代码不同处:j=ex[po]+po-i;*/
if(j < 0)j = 0; //如果i>po+next[po],则要从头开始匹配
while(i + j < len && str[j] == str[j + i]) //计算next[i] /*与EXKMP代码不同处:i+j<len&&j<l2&&s1[j+i]==s2[j]*/
j++;
next[i] = j;/*与EXKMP代码不同处:ex[i]=j;*/
po = i; //更新po的位置
}
}
}
//计算extend数组
void EXKMP(char *s1, char *s2)
{
int i = 0, j, po, len = strlen(s1), l2 = strlen(s2);
GETNEXT(s2);//计算子串的next数组
while(s1[i] == s2[i] && i < l2 && i < len) //计算ex[0]
i++;
ex[0] = i;
po = 0; //初始化po的位置
for(i = 1; i < len; i++)
{
if(next[i - po] + i < ex[po] + po) //第一种情况,直接可以得到ex[i]的值
ex[i] = next[i - po];
else//第二种情况,要继续匹配才能得到ex[i]的值
{
j = ex[po] + po - i;
if(j < 0)j = 0; //如果i>ex[po]+po则要从头开始匹配
while(i + j < len && j < l2 && s1[j + i] == s2[j]) //计算ex[i]
j++;
ex[i] = j;
po = i; //更新po的位置
}
}
}
int main()
{
int T;
while(~scanf("%d",&T))
{
while(T--)
{
long long sum = 0;
scanf("%s",s);
EXKMP(s,s);
for(int i=1;i<strlen(s);i++)
{
if(i + ex[i] == strlen(s))
{
sum += ex[i];
}
else
sum += ex[i]+1;
}
printf("%lld\n",sum);
}
}
return 0;
}