[NOI2014]动物园(KMP)
题意
题解
因为,一直用j=nxt[j]来遍历,可以遍历前i个字符所有相等的前后缀长度,所以有一个暴力的想法,就是对于每一个长度,开始遍历,记录长度小于i/2的相等的前后缀数量,最后累加即可。
但显然超时了。
换一种思路,其实我们要的只是长度小于i/2的相等的前后缀数量。
然后我们可以利用KMP的方法求出一个新的nxt数组,代表前i个数中最大的,且长度不超过i/2的相等的前后缀的长度。
对于每一个长度i,我们在预处理出前i个字符中前缀等于后缀的数量num[i]。那么每一个长度对答案的贡献为num[新nxt[i]]+1;
1 #include<iostream> 2 #include<cmath> 3 #include<cstdio> 4 #include<cstring> 5 #include<algorithm> 6 using namespace std; 7 const int N=1001000; 8 const int mod=1e9+7; 9 int t; 10 char s[N]; 11 int num[N],nxt[N]; 12 int main(){ 13 scanf("%d",&t); 14 while(t--){ 15 scanf("%s",s+1); 16 int len=strlen(s+1); 17 nxt[1]=0; 18 num[1]=1; 19 num[0]=0; 20 for(int i=2,j=0;i<=len;i++){ 21 while(j&&s[j+1]!=s[i])j=nxt[j]; 22 if(s[i]==s[j+1])j++; 23 nxt[i]=j; 24 num[i]=num[j]+1; 25 } 26 long long ans=1; 27 for(int i=2,j=0;i<=len;i++){ 28 while(j&&s[i]!=s[j+1])j=nxt[j]; 29 if(s[j+1]==s[i])j++; 30 while(j*2>i)j=nxt[j]; 31 ans=(ans*(long long)(num[j]+1))%mod; 32 } 33 printf("%lld\n",ans); 34 } 35 return 0; 36 }