您的位置:首页 > 其它

BZOJ 3670 [Noi2014] 动物园 KMP

2017-01-13 10:33 393 查看
题目大意:给出一个长为n的字符串(n<=1e6),求num数组的累乘和模 1,000,000,007,其中num(i)={长度为i的前缀中字符串S’ 的数量,其中S ‘既是该前缀的前缀也是该前缀的后缀,且该后缀与该前缀不重叠}

题目背景已经铺垫了,该题可以用KMP解决。

在计算nxt数组时,我们可以顺便计算出cnt数组(跳几次nxt到0),表示有多少前缀可以匹配到当前前缀包含的后缀,举个例子,niconiconi这个字符串中,nxt(10)=6,nxt(6)=2,nxt(2)=0,那么cnt(10)=3.表示长度分别为10(niconiconi)/6(niconi)/2(ni)的3个前缀可以在长度为10的前缀中找到一个后缀与其匹配。

cnt数组并不是num数组,因为会有不满足条件的字符串计算在内,所以再次进行匹配,将不满足条件的去掉,也就是要满足fix(已经匹配的前缀长度)*2 < i(当前前缀的长度),此时统计答案即可。

#include <cstdio>
#include <cstring>
#define N 1000005
#define MOD 1000000007
using namespace std;
typedef long long LL;
char s
;
int nxt
,cnt
;
LL KMP() {
memset(nxt,0,sizeof nxt);
LL ans=1; cnt[1]=1;
int len=strlen(s+1),fix=0;
for(int i=2;i<=len;i++) {
while(s[i]!=s[fix+1] && fix) fix=nxt[fix];
if(s[i]==s[fix+1]) fix++;
nxt[i]=fix;
cnt[i]=cnt[fix]+1;
}
fix=0;
for(int i=2;i<=len;i++) {
while(s[i]!=s[fix+1] && fix) fix=nxt[fix];
if(s[i]==s[fix+1]) fix++;
while(fix*2>i) fix=nxt[fix];
ans*=cnt[fix]+1;
ans%=MOD;
}
return ans;
}
int main() {
int T;
scanf("%d",&T);
while(T--) scanf("%s",s+1) , printf("%lld\n",KMP());
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  kmp