bzoj3670[Noi2014]动物园

bzoj3670[Noi2014]动物园

题意:

对于字符串S的前i个字符构成的子串,既是它的后缀同时又是它的前缀,并且该后缀与该前缀不重叠,将这种字符串的数量记作num[i]。给出字符串S求所有num[i]+1的乘积模1000000007。字符串长度≤1000000

题解:

先求一遍fail函数,得到数组记为next1,然后再求next2数组,表示满足next1[j]*2≤i的next1[j],这一过程也是可以递推的。同时用cnt数组记录next1[j]有多少个。num[i]就是cnt[next2[i]]。

代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #define maxn 1000100
 5 #define inc(i,j,k) for(int i=j;i<=k;i++)
 6 #define mod 1000000007
 7 using namespace std;
 8 
 9 char s[maxn]; int next1[maxn],next2[maxn],cnt[maxn],t,len; long long ans;
10 int main(){
11     scanf("%d",&t);
12     while(t--){
13         scanf("%s",s+1); len=strlen(s+1); next1[1]=0; cnt[1]=1; next2[1]=0;
14         inc(i,2,len){
15             int j=next1[i-1]; while(j&&s[j+1]!=s[i])j=next1[j];
16             if(s[j+1]==s[i])next1[i]=j+1,cnt[i]=cnt[next1[i]]+1;else next1[i]=0,cnt[i]=1;
17         }
18         inc(i,2,len){
19             int j=next2[i-1]; if(j*2+2>i)j=next1[j]; while(j&&s[j+1]!=s[i])j=next1[j];
20             if(s[j+1]==s[i])next2[i]=j+1;else next2[i]=0;
21         }
22         ans=1; inc(i,1,len)ans=ans*(cnt[next2[i]]+1)%mod; printf("%lld\n",ans);
23     }
24     return 0;
25 }

 

20160806

posted @ 2016-08-25 22:15  YuanZiming  阅读(298)  评论(0编辑  收藏  举报