题目链接: http://uoj.ac/problem/5
题意: 中文题目
解法:
如果num数组记载的前后缀允许重叠,是可以在递推next数组时顺路O(L)求出来的,这一步还算比较简单。
重点在于如何通过这个允许重叠的num数组求出不允许重叠时对应的num值。方法是让整个串再自己匹配自己一次,不过每次匹配时,如果j+1>(i+1)/2,即发现有重叠时,也要沿着next走。如果匹配成功,即str[i]==str[j],则说明i的num值应该是num[j]的值(因为也是这样递推算过来的),相乘即可;若匹配不成功,说明此时i的num值为0,答案要乘上1所以可以忽略。
//NOIP 2014
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1000010;
const int mod = 1000000007;
char s[maxn];
int fail[maxn], nxt[maxn];
long long ans;
int main()
{
int t; scanf("%d", &t);
while(t--){
ans = 1;
scanf("%s", s+1);
int len = strlen(s+1);
int j = 0;
memset(fail, 0, sizeof(fail));
memset(nxt, 0, sizeof(nxt));
nxt[1] = 1;
for(int i = 2; i <= len; i++){
while(s[j+1] != s[i] && j > 0) j = fail[j];
if(s[j+1] == s[i]) j++;
fail[i] = j;
nxt[i] = nxt[j]+1;
}
j = 0;
for(int i = 2; i <= len; i++){
while(s[j+1]!=s[i]&&j>0) j = fail[j];
if(s[j+1]==s[i]) j++;
while((j<<1)>i&&j>0) j = fail[j];
ans = (ans*(nxt[j]+1))%mod;
}
printf("%lld\n", ans);
}
return 0;
}