题目大意:
对于字符串S的前i个字符构成的子串,既是它的后缀同时又是它的前缀,并且该后缀与该前缀不重叠,将这种字符串的数量记作num[i]。
求所有num[]的乘积对1000000007取模。
solution:
根据next数组的定义,我们可以暴力跳next。
50分代码:
#include<cstdio>
#include<cstring>
using namespace std;
int t,n,w,next[1000005];
char a[1000005];
const long long mod=1000000007;
long long ans=1;
void get(){
n=strlen(a+1);
next[1]=0;
for (register int i=2;i<=n;++i){
w=next[i-1];
while (a[w+1]!=a[i]&&w>=1) w=next[w];
if (a[w+1]==a[i]) next[i]=w+1;
else next[i]=0;
}
}
int main(){
scanf ("%d",&t);
while (t--){
scanf ("%s",a+1);ans=1ll;get();
for (register int i=1;i<=n;++i){
int s=0,j=i;
while (j){
if (j<=i/2) ++s;
j=next[j];
}
ans=ans*(s+1)%mod;
}
printf ("%lld\n",ans);
}
return 0;
}
暴力不可行啊www,但既然题目描述里都介绍了kmp那肯定要往这方面想啊。
令f[i]表示从i位置最多能够往前跳的次数,显然f[i]=f[next[i]]+1。
每次沿着前一个字符的next跳,直到找到一个合法的位置。
这样的复杂度近似O(n)。
#include<cstdio>
#include<cstring>
using namespace std;
int t,n,w,next[1000005],num[1000005];
char a[1000005];
const long long mod=1000000007;
long long ans=1;
void get(){
n=strlen(a+1);
next[1]=0;
for (register int i=2;i<=n;++i){
w=next[i-1];
while (a[w+1]!=a[i]&&w>=1) w=next[w];
if (a[w+1]==a[i]) next[i]=w+1;
else next[i]=0;
}
}
int main(){
scanf ("%d",&t);
while (t--){
scanf ("%s",a+1);ans=1ll;get();
num[1]=1;
for (register int i=2;i<=n;++i){
num[i]=num[next[i]]+1;
}
for (register int i=2,k=0;i<=n;++i){
while (k&&a[k+1]!=a[i]) k=next[k];
if (a[i]==a[k+1]) ++k;
while (k*2>i) k=next[k];
ans=ans*(num[k]+1)%mod;
}
printf ("%lld\n",ans);
}
return 0;
}