BZOJ3670 [NOI2014]动物园 [KMP]

BZOJ3670 [NOI2014]动物园 [KMP]

题目描述

题目传送门

题解

这道题主要利用了Fail数组(本题中的next数组)的性质。

熊猫:“对于字符串S的前i个字符构成的子串,既是它的后缀又是它的前缀的字符串中(它本身除外),最长的长度记作next[i]。”

num[i] n u m [ i ] 表示字符串的前 i i 位中前缀和后缀相等的字符串个数(没有“不重叠”的限制)。显然有:num[i]=num[Fail[i]]+1,其中 +1 + 1 是因为字符串本身是自己的后缀。

显然,当指向模式串的指针 j j 在模式串后半段时,[1,j]这个前缀一定与后缀重叠;而当 j j 指向模式串的前半段时,[1,j]这个前缀一定不与后缀重叠。所以在计算时,只要保证 j2i j ∗ 2 ≤ i ,这样的 num[j] n u m [ j ] 就符合题目的要求。

代码

只比普通的KMP多两行代码。

#include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long
#define N 1000100
using namespace std;
ll num[N],Fail[N];char s[N];
ll KMP(){
    ll len=strlen(s+1),Ans=1LL;
    for(ll i=1;i<=len;i++)Fail[i]=0,num[i]=0;
    num[1]=1LL;
    for(ll i=2,j=0;i<=len;i++){
        while(j && s[j+1]!=s[i])j=Fail[j];
        if(s[j+1]==s[i])j++;Fail[i]=j;
        num[i]=num[j]+1;
    }
    for(ll i=2,j=0;i<=len;i++){
        while(j && s[j+1]!=s[i])j=Fail[j];
        if(s[j+1]==s[i])j++;
        while(j && j*2>i)j=Fail[j];
        Ans=Ans*(num[j]+1)%(ll)(1e9+7);
    }
    return Ans;
}
int main(){
    ll n;scanf("%lld",&n);
    while(n--){
        scanf("%s",s+1);
        printf("%lld\n",KMP());
    }
    return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值