好,暴力能拿$50pts\space qwq$
暴力的思路就是一直跳$nxt[j]$,直到它的长度小于串的一半,然后开始计数,当然要接着跳$nxt[j]$
正解:考虑没有长度要求的(不要求不重合)公共前后缀的数目,显然$ans[i]=ans[j]+1$相当于$i$比$j$是多了$i$它本身。
所以求解时模仿$kmp$的过程,$num[i]$就是一直跳$nxt[j]$,然后直到$j<=\frac{i}{2}$,$num[i]=ans[j]$
注意,此处模仿$kmp$的原因是,能够避免跳过一些冗余的$nxt[j]$($nxt[j]$过大的情况),对于下一次匹配,上一次的$j$就是上一次的小于等于$\frac{i}{2}$的最长公共前后缀的长度,如果还能匹配就直接匹配,过长了再跳一下$nxt[j]$,否则就一直跳$nxt[j]$,直到匹配。
#include<cstdio> #include<iostream> #include<algorithm> #include<cstring> #include<cmath> #include<cctype> #include<cstdlib> #include<vector> #include<queue> #include<map> #include<set> #define ull unsigned long long #define ll long long #define R register int #define pause for(R i=1;i<=10000000000;++i) using namespace std; namespace Fread { static char B[1<<15],*S=B,*D=B; #define getchar() (S==D&&(D=(S=B)+fread(B,1,1<<15,stdin),S==D)?EOF:*S++) inline int g() { R ret=0,fix=1; register char ch; while(!isdigit(ch=getchar())) fix=ch=='-'?-1:fix; do ret=ret*10+(ch^48); while(isdigit(ch=getchar())); return ret*fix; } inline bool isempty(const char& ch) {return ch<=36||ch>=127;} inline void gs(char* s) {register char ch; while(isempty(ch=getchar())); do *s++=ch; while(!isempty(ch=getchar()));} }using Fread::g; using Fread::gs; const int M=1000000007; int n,nxt[1000010],ans[1000010]; char s[1000010]; ll num=1; inline void PRE() { nxt[1]=0; for(R i=2,j=0;i<=n;++i) { while(j&&s[i]!=s[j+1]) j=nxt[j]; if(s[i]==s[j+1]) ++j; nxt[i]=j; ans[i]=ans[j]+1; } } inline void calc() { for(R i=2,j=0;i<=n;++i) { while(j&&s[i]!=s[j+1]) j=nxt[j]; if(s[i]==s[j+1]) ++j; while(j>i/2) j=nxt[j]; (num*=(ans[j]+1))%=M; } } signed main() { #ifdef JACK freopen("NOIPAK++.in","r",stdin); #endif R t=g(); for(R i=1;i<=t;++i) { memset(s,0,sizeof(s)); num=1; gs(s+1); n=strlen(s+1); ans[1]=1; PRE(); // for(R i=2;i<=n;++i) { R lim=i/2,j=i,cnt=0; // while(j) {j=nxt[j]; if(j&&j<=lim) ++cnt;} // (ans*=(cnt+1))%=M; // } calc(); printf("%lld\n",num); } }
2019.06.15