测试地址:动物园
做法:这题目很迷,一开始以为想出一种不用预处理的求num的方法,事实证明是错的......
为了方便,设prefix(s,i)为字符串s的前i个字符组成的前缀,suffix(s,i)为字符串s的后i个字符组成的后缀。
实际上我们要先求一个“假”的num数组,我们把它称为cnt数组,cnt[i]表示prefix(s,i)中既是其前缀又是其后缀的字符串个数(包括自身),于是我们就先预处理出next数组和cnt数组,然后再做一遍类似KMP的过程,这时候再注意重叠的问题:设pre为当前最大的满足prefix(prefix(s,i),pre)=suffix(prefix(s,i),pre)且pre≠i的数,如果pre*2>i,表示有重叠,则按照KMP的方法修正pre直到满足条件为止。于是我们可以知道,prefix(prefix(s,i),pre)=suffix(prefix(s,i),pre)且不重叠,且此时pre是满足条件的最大数,这时就可以得出num[i]=cnt[pre],累加答案即可。
以下是本人代码:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define p 1000000007
using namespace std;
char s[1000010];
int n,len;
long long cnt[1000010],next[1000010],ans;
void kmp()
{
int pre=0;
next[1]=cnt[0]=0;ans=1;
cnt[1]=1;
for(int i=2;i<=len;i++)
{
while(pre&&s[pre+1]!=s[i]) pre=next[pre];
if (s[pre+1]==s[i]) pre++;
next[i]=pre;
cnt[i]=cnt[pre]+1;
}
pre=0;ans=1;
for(int i=2;i<=len;i++)
{
while(pre&&s[pre+1]!=s[i]) pre=next[pre];
if (s[pre+1]==s[i]) pre++;
while((pre<<1)>i) pre=next[pre];
ans*=cnt[pre]+1;
ans%=p;
}
printf("%lld\n",ans);
}
int main()
{
scanf("%d",&n);
s[0]='_';
while(n--)
{
scanf("%s",s+1);
len=strlen(s)-1;
kmp();
}
return 0;
}