BZOJ 3670 NOI2014 动物园 KMP+dp

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3670

 

题意概述:令num[i]表示字符串由1~i的字符形成的前缀中不相重叠的相同前后缀的数量,求mul{ num[i] | 1<=i<=L }mod1000000007。

 

实际上只要对KMP理解的好这就是个水题,可以想到dp求得num数组,num[i]=num[f[i]]+1,f[i]表示字符串的前缀1~i形成的不重叠的最长相同前后缀长度,如果f[i]=0的话就不存在。题目的提醒实际上很明显,想想KMP,发现这个也是一个用失配函数来匹配自己的过程。在推算f[i+1]的时候,先令j=f[i],这样做直接保证了长度限制,并且如果可以匹配成功一定是最优的。然后在fail函数上匹配,直到成功为止。这个时候j后移一位,判断一下长度限制,如果不符合在fail上面再回跳一次。

主要是用到了fail函数一种理解方式:f[i]表示的是前i个字符最长相同前后缀长度。(这个前后缀是不包括原串的)

 

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cstdlib>
 5 #include<algorithm>
 6 #include<cmath>
 7 #include<queue>
 8 #include<set>
 9 #include<map>
10 #include<vector>
11 #include<cctype>
12 using namespace std;
13 const int maxn=1000005;
14 const int mo=1000000007;
15 
16 int N,f1[maxn],f2[maxn],h[maxn];
17 char S[maxn];
18 
19 void getfail(char *p)
20 {
21     int m=strlen(p);
22     f1[0]=f1[1]=0;
23     for(int i=1;i<m;i++){
24         int j=f1[i];
25         while(j&&p[j]!=p[i]) j=f1[j];
26         f1[i+1]=p[j]==p[i]?j+1:0;
27     }
28     f2[0]=f2[1]=0;
29     for(int i=1;i<m;i++){
30         int j=f2[i];
31         while(j&&(p[j]!=p[i])) j=f1[j];
32         if(p[j]==p[i]) j++;
33         if(j*2>i+1) j=f1[j];
34         f2[i+1]=j;
35     }
36 }
37 int main()
38 {
39     scanf("%d\n",&N);
40     for(int i=1;i<=N;i++){
41         gets(S); getfail(S);
42         int n=strlen(S);
43         h[1]=0;
44         for(int i=2;i<=n;i++) h[i]=h[f1[i]]+(f1[i]?1:0);
45         int ans=1;
46         for(int i=1;i<=n;i++) ans=(1ll*ans*(h[f2[i]]+(f2[i]?1:0)+1))%mo;
47         printf("%d\n",ans);
48     }
49     return 0;
50 }

 

posted @ 2018-03-04 18:22  KKKorange  阅读(128)  评论(0编辑  收藏  举报