介绍
一个和马拉车算法很像的东西,可以O(n)O(n)O(n)求出一个串的所有后缀与前缀的匹配长度。
适用场合:
求出某个字符串的mmm个子串与另外一个串的最长匹配长度(从前往后或从后往前)
因为往后扩不会返回,右端点一直加,所以时间复杂度为O(N)O(N)O(N)
两个串的情况
如果要匹配两个串,串xxx的所有后缀匹配串yyy的前缀,只需要使用特殊字符将xxx连到yyy后面即可。
orginal link - http://acm.hdu.edu.cn/showproblem.php?pid=6629
题意:
求第二位置开始的后缀与前缀的公共串长度LLL,∑min(L+1,pL)\sum min(L+1,pL)∑min(L+1,pL)(pLpLpL为后缀长度)
代码:
/*
* Author : Jk_Chen
* Date : 2019-08-20-11.00.34
*/
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define rep(i,a,b) for(int i=(int)(a);i<=(int)(b);i++)
#define per(i,a,b) for(int i=(int)(a);i>=(int)(b);i--)
#define mmm(a,b) memset(a,b,sizeof(a))
#define pb push_back
#define pill pair<int, int>
const LL mod=1e9+7;
const int maxn=1e6+9;
LL rd(){ LL z=0; char last=' ',ch=getchar();
while(!(ch>='0' && ch<='9'))last=ch,ch=getchar();
while(ch>='0' && ch<='9')z=z*10+ch-'0',ch=getchar();
if(last=='-')z=-z; return z;
}
/*_________________________________________________________head*/
char str[maxn];
int len;
int z[maxn];
void deal(){ // Z Algorithm
int l=0,r=1;
z[0]=0;
rep(i,1,len-1){
if(r>i)z[i]=min(z[i-l],r-i);
if(z[i]+i>=r){
l=i,r=z[i]+i;
while(r<len&&str[r]==str[r-l])r++;
z[i]=r-l;
}
}
z[0]=len;
}
int main(){
int t=rd();
while(t--){
gets(str);
len=strlen(str);
deal();
LL sum=0;
rep(i,1,len-1){
if(!z[i])sum++;
else if(z[i]==len-i)sum+=z[i];
else sum+=z[i]+1;
}
printf("%lld\n",sum);
}
return 0;
}