求这玩意:
对于字符串S的前i个字符构成的子串,既是它的后缀同时又是它的前缀,并且该后缀与该前缀不重叠,将这种字符串的数量记作num[i]
对1,000,000,007取模的结果
n≤5,L≤1,000,000
发现$num[i]$有和$fail[i]$类似的递增性质,$num[i]<num[i-1]+1$
然后$KMP$之后$fail$递推出$sum[i]$为$i$的$fail$祖先有几个
再类似求$fail$的过程求一遍$num$,只是多了判断$2*j le i$,用$sum[j]$更新答案就行了
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <bitset> using namespace std; typedef long long ll; const int N=1e6+5,MOD=1e9+7; int n; char s[N]; int fail[N],sum[N]; void KMP(){ fail[1]=0; for(int i=2;i<=n;i++){ int j=fail[i-1]; while(j&&s[i]!=s[j+1]) j=fail[j]; fail[i]=s[i]==s[j+1]?j+1:0; } sum[0]=0; for(int i=1;i<=n;i++) sum[i]=sum[fail[i]]+1; //for(int i=1;i<=n;i++) printf("hi %d %d %d ",i,fail[i],sum[i]); int j=0; ll ans=1; for(int i=2;i<=n;i++){ while(j&&s[i]!=s[j+1]) j=fail[j]; if(s[i]==s[j+1]) j++; while((j<<1)>i) j=fail[j];//printf("j %d ",j); ans=ans*(sum[j]+1)%MOD; } printf("%lld ",ans); } int main(){ freopen("in","r",stdin); int T;scanf("%d",&T); while(T--){ scanf("%s",s+1); n=strlen(s+1); KMP(); } }