BZOJ--3670(KMP,变形)
2014-12-16 02:18:06
思路:bzoj果然都是好题....poj刷了几道kmp感觉自己基本掌握了,直到刷bzoj才知道自己的理解是有多么弱!
这题需要从kmp定义出发来思考,在kmp过程中同时维护一个cnt数组,cnt[i]用来计算从i出发,不断i=P[i],需要几步达到0(相当于返回0的距离)
这个cnt[i]的含义其实就是前i个字符组成的串,能找到多少个前缀使得有后缀与之相等(思考!)
那么由于题目中的不重叠的限制,我们只要利用j = P[j],使得有最大的j使得:j * 2 <= i,那么num[i]=cnt[j]+1,这个j是随着循环不断维护的,所以不用每次都从i找回去。
1 /************************************************************************* 2 > File Name: b3670.cpp 3 > Author: Natureal 4 > Mail: 564374850@qq.com 5 > Created Time: Mon 15 Dec 2014 10:33:20 PM CST 6 ************************************************************************/ 7 8 #include <cstdio> 9 #include <cstring> 10 #include <cstdlib> 11 #include <cmath> 12 #include <vector> 13 #include <map> 14 #include <set> 15 #include <stack> 16 #include <queue> 17 #include <iostream> 18 #include <algorithm> 19 using namespace std; 20 #define lp (p << 1) 21 #define rp (p << 1|1) 22 #define getmid(l,r) (l + (r - l) / 2) 23 #define MP(a,b) make_pair(a,b) 24 typedef long long ll; 25 typedef unsigned long long ull; 26 const int INF = 1 << 30; 27 const int maxn = 1000010; 28 29 int n,len; 30 int P[maxn],cnt[maxn]; 31 char s[maxn]; 32 ll ans; 33 34 int main(){ 35 scanf("%d",&n); 36 while(n--){ 37 scanf("%s",s + 1); 38 ans = 0; 39 len = strlen(s + 1); 40 P[1] = 0; 41 int j = 0; 42 cnt[1] = 1; 43 for(int i = 2; i <= len; ++i){ 44 while(j > 0 && s[j + 1] != s[i]) j = P[j]; 45 if(s[j + 1] == s[i]) j++; 46 P[i] = j; 47 cnt[i] = cnt[j] + 1; 48 } 49 j = 0; 50 ans = 1; 51 for(int i = 2; i <= len; ++i){ 52 while(j > 0 && s[j + 1] != s[i]) j = P[j]; 53 if(s[j + 1] == s[i]) j++; 54 while((j << 1) > i) j = P[j]; 55 ans *= cnt[j] + 1; 56 ans %= 1000000007; 57 } 58 printf("%lld\n",ans); 59 } 60 return 0; 61 }