http://www.lydsy.com/JudgeOnline/problem.php?id=3670
法一:KMP+st表
抽离nxt数组,构成一棵树
若nxt[i]=j,则i作为j的子节点
那么num[i] 就是i到根节点的路径上,所有<=i/2 的节点的个数
这棵树的点随深度的递增而增大
所以用st表存这棵树
st 表 开[logn][n],常数优化求st表的过程
#include<cmath> #include<cstdio> #include<cstring> #define N 1000001 using namespace std; const int mod=1e9+7; char s[N]; int len; int f[N]; int dep[N],st[21][N]; int num[N]; void get_next() { int j; for(int i=1;i<len;++i) { j=f[i]; while(j && s[i]!=s[j]) j=f[j]; f[i+1]= s[j]==s[i] ? j+1 : 0; } } void solve() { for(int i=1;i<=len;++i) st[0][i]=f[i],dep[i]=dep[f[i]]+1; int lim=1.0*log(len)/log(2); for(int j=1;j<=lim;++j) for(int i=1;i<=len;++i) st[j][i]=st[j-1][st[j-1][i]]; int now; for(int i=1;i<=len;++i) { now=i; for(int j=lim;j>=0;--j) if(st[j][now]*2>i) now=st[j][now]; num[i]=dep[now]-1; } int ans=1; for(int i=1;i<=len;++i) ans=1LL*ans*(num[i]+1)%mod; printf("%d\n",ans); } int main() { //freopen("data.in","r",stdin); //freopen("my.out","w",stdout); int T; scanf("%d",&T); while(T--) { scanf("%s",s); len=strlen(s); get_next(); solve(); } }