码迷,mamicode.com
首页 > 其他好文 > 详细

【NOI2014】动物园

时间:2017-11-12 23:06:34      阅读:142      评论:0      收藏:0      [点我收藏+]

标签:col   i++   main   表示   span   地方   logs   解释   str   

 这道题因为自己把1000000007写成了100000007而浪费了三个小时,所以告诫自己:数一下几位!数一下几位!数一下几位!

先贴代码~

 1 #include<cstdio>
 2 #include<cstring>
 3 #define mod 1000000007 //该看眼科了... 
 4 #define LL long long
 5 int next[1000005],cnt[1000005],n;
 6 LL ans;                //cnt[i]表示前i个字符公共前后缀的数目,包括自己!也就是说cnt[i]至少为1(i!=0)(至于为什么要这样做,在(2)中解释)
 7 char s[1000005];
 8 void getcnt(int l){    //getcnt:获取常规的next[],同时得到cnt[] ——(#)
 9     next[0]=-1;
10     cnt[0]=0;
11     int i=0,k=-1;
12     while(i<l){
13         while(k>=0&&s[k]!=s[i]) k=next[k];
14         i++,k++;
15         next[i]=k;
16         cnt[i]=cnt[k]+1;
17     }
18 }
19 void solve(int l){     //solve:大体上是再求一遍next[]的过程,每次可以得到要求的num[],这里有两个问题: 
20     ans=1;             //1.为什么不能在最外层while每次开始的时候用k=next[i],而要再像求next[]那样求一遍,直接用不会更快吗? ——(1)
21     int k=-1,i=0;
22     while(i<l){        //2.num[i]是怎样通过cnt[i]得到的? ——(2)
23         while(k>=0&&s[k]!=s[i]) k=next[k];
24         k++,i++;
25         while(2*k>i) k=next[k];
26         ans=ans*(LL)(cnt[k]+1)%mod;
27     }
28     printf("%lld\n",ans);
29 }
30 int main()
31 {
32     scanf("%d",&n);
33     while(n--){
34         scanf("%s",s);
35         int l=strlen(s);
36         getcnt(l);
37         solve(l);
38     }
39 }

现在来一一解释上面的三个地方。

题目要求的是数量,自然就可以想到next[]数组的意义:最长公共前后缀长度,也就是next[i]即前i个字符的最长公共前后缀长度。

现在我们假定对i已经知道了next[i](现在只把它看成一个数字),注意到前i个字符的前next[i]个和后next[i]个字符是相等的,我们要求的是所有的公共前后缀,既然next[i]是最长的一个,又注意到next[next[i]]是前next[i]个字符的最长公共前后缀,从而我们可以推出,前i个字符中的前next[next[i]]和后next[next[i]]个字符也是相同的。也就说,我们可以递推地求解前i个字符的公共前后缀数量,由于next[]数组的最长性质,我们保证一定可以取遍所有的公共前后缀。实际上这也是用next[]数组求解周期串问题的核心思想。

现在我们可以解答(#)了,假设我们已经知道k=next[i](始终把next[i]看成一个数字,就像定积分是一个数字一样(逃...)和前i-1个字符每个字符的cnt[]值(这个是我们递推的依据),从而可以得到:

cnt[i]=cnt[k]+1


cnt[k]是好理解的,就是前k个字符的所有公共前后缀数量(也就是我们现在查考的前i个字符的最长公共前后缀[0,...,k-1]的公共前后缀数量),由上面的分析我们知道了,前k个字符的公共前后缀就是前i个字符的公共前后缀,再加上前i个字符本身(为什么要加自己?这样不就不满足长度不超过i/2了吗?这个问题留到(2)解答),就得到了上面的递推式,从而可以通过初始化cnt[0]=0(显然不存在前0个字符这种说法的嘛)而得到所有的cnt[i],1<=i<=strlen(s)

下面来解答(1)和(2)这两个问题。

未完待 续……

【NOI2014】动物园

标签:col   i++   main   表示   span   地方   logs   解释   str   

原文地址:http://www.cnblogs.com/sulley/p/7823199.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!