题目大意:给出一个长为n的字符串(n<=1e6),求num数组的累乘和模 1,000,000,007,其中num(i)={长度为i的前缀中字符串S’ 的数量,其中S ‘既是该前缀的前缀也是该前缀的后缀,且该后缀与该前缀不重叠}
题目背景已经铺垫了,该题可以用KMP解决。
在计算nxt数组时,我们可以顺便计算出cnt数组(跳几次nxt到0),表示有多少前缀可以匹配到当前前缀包含的后缀,举个例子,niconiconi这个字符串中,nxt(10)=6,nxt(6)=2,nxt(2)=0,那么cnt(10)=3.表示长度分别为10(niconiconi)/6(niconi)/2(ni)的3个前缀可以在长度为10的前缀中找到一个后缀与其匹配。
cnt数组并不是num数组,因为会有不满足条件的字符串计算在内,所以再次进行匹配,将不满足条件的去掉,也就是要满足fix(已经匹配的前缀长度)*2 < i(当前前缀的长度),此时统计答案即可。
#include <cstdio>
#include <cstring>
#define N 1000005
#define MOD 1000000007
using namespace std;
typedef long long LL;
char s[N];
int nxt[N],cnt[N];
LL KMP() {
memset(nxt,0,sizeof nxt);
LL ans=1; cnt[1]=1;
int len=strlen(s+1),fix=0;
for(int i=2;i<=len;i++) {
while(s[i]!=s[fix+1] && fix) fix=nxt[fix];
if(s[i]==s[fix+1]) fix++;
nxt[i]=fix;
cnt[i]=cnt[fix]+1;
}
fix=0;
for(int i=2;i<=len;i++) {
while(s[i]!=s[fix+1] && fix) fix=nxt[fix];
if(s[i]==s[fix+1]) fix++;
while(fix*2>i) fix=nxt[fix];
ans*=cnt[fix]+1;
ans%=MOD;
}
return ans;
}
int main() {
int T;
scanf("%d",&T);
while(T--) scanf("%s",s+1) , printf("%lld\n",KMP());
return 0;
}