【NOI2014】动物园

题目链接:http://uoj.ac/problem/5


求:$${\prod _{i=1}^{L}num[i]\%(1e9+7)}$$,${num\left [ i \right ]}$表示:由字符串$S$的前$i$个字符构成的子串中,既是它的前缀,又是它的后缀,并且互不重合的字符串的个数。


 利用KMP算法求出$next$数组,同时求出$cnt$数组,$cnt$数组定义为:由字符串$S$的前$i$个字符构成的子串中,既是它的前缀,又是它的后缀,可以的字符串的个数。

 ${cnt[i]=cnt[next[i]]+1}$

 然后对于每一个位置,我们再做一遍形如找$next$数组的过程,但是这个时候指针一定要沿着$next$数组跳回到${\left \lfloor \frac{i}{2} \right \rfloor}$之前,我们知道对应点的$cnt$,那么这就满足了互不重合的条件,直接算贡献即可。


 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<vector>
 5 #include<cstdlib>
 6 #include<cmath>
 7 #include<cstring>
 8 using namespace std;
 9 #define maxn 1001000
10 #define llg long long
11 #define md 1000000007 
12 #define yyj(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
13 llg n,m,next[maxn],T;
14 char s[maxn];
15 llg cnt[maxn];//既是1~i的后缀又是它的前缀的字符串个数
16 
17 void find_next()
18 {
19     llg k=0;
20     next[1]=0; cnt[1]=1;
21     for (llg i=2;i<=n;i++)
22     {
23         while (k && s[k+1]!=s[i]) k=next[k];
24         if (s[k+1]==s[i]) k++;
25         next[i]=k; 
26         cnt[i]=cnt[k]+1;
27     }
28 }
29 
30 llg work()
31 {
32     llg k=0,ans=1;
33     for (llg i=2;i<=n;i++)
34     {
35         while (k && s[k+1]!=s[i]) k=next[k];
36         if (s[k+1]==s[i]) k++;
37         while (k*2>i) k=next[k];
38         ans=ans*(cnt[k]+1);
39         ans%=md;
40     }
41     return ans;
42 }
43 
44 int main()
45 {
46     yyj("a");
47     cin>>T;
48     while (T--)
49     {
50         scanf("%s",s+1);
51         n=strlen(s+1);
52         find_next();
53         printf("%lld\n",work());
54     }
55     return 0;
56 }

 

posted @ 2017-02-10 08:57  №〓→龙光←  阅读(118)  评论(0编辑  收藏  举报