【题解】
这里首先定义失配指针f[i]满足:第i个位置的字符与第f[i]位相同,字符数组从1开始
如:aba f[1]=0,f[2]=0,f[3]=1
要求出num[i],只需延f指针上溯,找到所有长度不超过i/2的位置,它的数目即为num[i]
可以考虑fail树的思想,用cnt[i]记录从i延失配指针上溯,能遇到的结点数目
找出最大的长度不超过i/2的位置j,则num[i]=cnt[j]+1
倍增法即可找出
然而复杂度为:O( n*L*log(L) ),会TLE掉
只能从递推的角度考虑了
设next[i]表示:从i延失配指针上溯遇到的第一个度不超过i/2的位置
类似kmp再做一遍即可求出该数组
【代码】
两遍KMP满分的:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MOD 1000000007ll
char s[1000005];
int f[1000005],cnt[1000005],next[1000005];
int main()
{
long long ans;
int n,L,i,j;
scanf("%d",&n);
for(;n>0;n--)
{
scanf("%s",s);
L=strlen(s);
for(i=L;i>=1;i--)
s[i]=s[i-1];
f[1]=0;
for(i=1;i<L;i++)
{
j=f[i];
while(s[j+1]!=s[i+1]&&j>0) j=f[j];
if(s[j+1]==s[i+1]) f[i+1]=j+1;
else f[i+1]=0;
}
cnt[0]=0;
for(i=1;i<=L;i++)
cnt[i]=cnt[f[i]]+1;
next[1]=0;
for(i=1;i<=L;i++)
{
j=next[i];
if(j<<1==i) j=f[j];
while(s[j+1]!=s[i+1]&&j>0) j=f[j];
if(s[j+1]==s[i+1]) next[i+1]=j+1;
else next[i+1]=0;
}
ans=1;
for(i=1;i<=L;i++)
ans=(ans*((long long)cnt[next[i]]+1LL))%MOD;
printf("%lld\n",ans);
}
return 0;
}
另附一个倍增的,猥琐地TLE了3个点 TAT :
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MOD 1000000007ll
char s[1000005];
int f[1000005][25],cnt[1000005];
int main()
{
long long ans;
int n,L,i,j,k;
scanf("%d",&n);
for(;n>0;n--)
{
scanf("%s",s);
L=strlen(s);
for(i=L;i>=1;i--)
s[i]=s[i-1];
f[1][0]=0;
for(i=1;i<L;i++)
{
j=f[i][0];
while(s[j+1]!=s[i+1]&&j>0) j=f[j][0];
if(s[j+1]==s[i+1]) f[i+1][0]=j+1;
else f[i+1][0]=0;
}
cnt[0]=0;
for(i=1;i<=L;i++)
cnt[i]=cnt[f[i][0]]+1;
for(i=1;i<=20;i++)
for(j=1;j<=L;j++)
f[j][i]=f[f[j][i-1]][i-1];
ans=1;
for(i=1;i<=L;i++)
{
j=f[i][0];
while(j>i>>1)
{
for(k=1;f[j][k]>i>>1;k++);
j=f[j][k-1];
}
ans=(ans*((long long)cnt[j]+1LL))%MOD;
}
printf("%lld\n",ans);
}
return 0;
}