【KMP】BZOJ3670-[Noi2014]动物园

【题目大意】
[依然借用别人的概括]给定一个长为L的字符串(L<=100W),求一个num数组,num[i]表示长度为i的前缀中字符串S’的数量,其中S‘既是该前缀的前缀也是该前缀的后缀,且|S'|*2<=i
【思路】
KMP中next数组的变形。先算一次next数组和dep数组,其中dep数组表示当前前缀经过j=next[j]可以到达-1,这个值其实就是num数组的雏形。然后再进行一次求解next数组,每次前缀不断进行j=next[j],直到满足|S'|*2<=i。此时的dep[j]就是当前前缀的num值,由于前一次求解next数组预处理,这个值可以在O(1)时间内求解。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #define LL long long
 6 #define mod 1000000007
 7 const int MAXN=1000000+500;
 8 using namespace std;
 9 int n;
10 char p[MAXN];
11 int next[MAXN],dep[MAXN],next2[MAXN];
12 int len;
13 
14 void getnext()
15 {
16     int i=0,j=-1;
17     next[i]=j;
18     dep[i]=0;
19     while (i<len)
20     {
21         if (j==-1 || p[i]==p[j])
22         {
23             dep[++i]=dep[++j]+1;
24             next[i]=j;
25         }
26         else j=next[j];
27     }
28 }
29 
30 void getans()
31 {
32     LL ans=1;
33     int i=0,j=-1;
34     while (i<len)
35     {
36         if (j==-1 || p[i]==p[j])
37         {
38             i++,j++;
39             while (j!=-1 && (j<<1)>i) 
40                 j=next[j];
41             if (j!=-1 && i!=-1) ans=ans*(LL)(dep[j]+1) % mod;
42         }
43         else j=next[j];
44     }
45     printf("%lld\n",ans);
46     
47 
48 }
49 
50 int main()
51 {
52     scanf("%d",&n);
53     for (int i=0;i<n;i++)
54     {
55         scanf("%s",p);
56         len=strlen(p);
57         getnext();
58         getans();
59     }
60     return 0;
61 }

 

posted @ 2016-03-26 19:52  iiyiyi  阅读(1298)  评论(0编辑  收藏  举报