传送门1
传送门2
写在前面:难得题面和题解是一致的算法
思路:原始想法是先KMP建next数组,同时记录1-len每个长度的“公共前缀后缀”的总和sum[i],很容易想到
sum[i]=1+sum[tmp]
,tmp就是长度为i的字符串中是前缀同时是后缀的字符串的长度(就是那个用next[next[…求的东西),之后判断长度1-len的next[i],如果next<i/2,
num[i]=sum[next[i]]
,不然就令next[i]=next[next[i]],继续判断,直到符合条件为止。
这种最简单粗暴的方式可以过50分,但我们发现如果原串是一个循环字符串而且循环节特别小,例如“aaaaaaaaaaa…”,那么每次求num时,next[i]是一个字符一个字符往前蹦达的,那也就是说最坏情况下时间复杂度会达到
O(len2)
,爆炸。(顺便说一下,蒟蒻就是被卡在这里好久,想到这个问题就头大,搞的忘记了next数组的性质,直接转移到next[i/2]上去了……竟然还能过样例)无法,蒟蒻选择看题解,发现题解的做法是把求next,sum放在一起,求答案(num)放在一起,开了两个循环,后来想了一下,求next,sum时tmp是从next[i]开始逐渐往后跳,时间复杂度均摊下来是
O(len)
,而求答案时完全可以类似于从前往后走,每次求num时前进最多一格,后退不确定,但总的复杂度是一定的且可以接受的。
注意:答案用long long保存,sum[1]=1(它自身就是一个哦)
#include<bits/stdc++.h>
#define mod 1000000007
using namespace std;
int tmp,T,len;
int sum[1000010],next[1000010];
long long ans;
char s[1000010];
main()
{
sum[1]=1;
scanf("%d",&T);
while (T--)
{
scanf("%s",s);
ans=1;tmp=0;
for (int i=1;s[i];i++)
{
tmp=next[i];
while (tmp&&s[tmp]!=s[i]) tmp=next[tmp];
tmp+=(s[i]==s[tmp]);
next[i+1]=tmp;
sum[i+1]=sum[tmp]+1;
}
for (int i=1;s[i];i++)
{
while (tmp&&s[tmp]!=s[i]) tmp=next[tmp];
tmp+=(s[i]==s[tmp]);
while (tmp>((i+1)>>1)) tmp=next[tmp];
ans=ans*(sum[tmp]+1)%mod;
}
printf("%lld\n",ans);
}
}