[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 } 

 

posted @ 2018-08-24 15:32  Xu-daxia  阅读(184)  评论(0编辑  收藏  举报