码迷,mamicode.com
首页 > 其他好文 > 详细

BZOJ_3670_[NOI2014]_动物园(kmp)

时间:2016-05-13 18:57:41      阅读:204      评论:0      收藏:0      [点我收藏+]

标签:

描述


http://www.lydsy.com/JudgeOnline/problem.php?id=3670

对于一个字符串,求出num数组,其中num[i]表示前i个字符构成的字串中不相重合的相同前后缀共有多少对.

 

分析


在做kmp的自匹配时,顺便记录一个cnt数组,其中cnt[i]表示第i个字符需要进行几次i=fail[i]到达0,也就是如果失配时跳转到i位置,包括i位置,之前共有多少可以作为失配时跳转对象的(也就是有多少满足和后面某一后缀相同的前缀).第二遍做子匹配时,将失配指针一直跳到小于等于i/2的位置j,此时cnt[j]就是共有多少满足的相同前缀后缀组即num[i].(手画画更清楚点?)

p.s.第二次匹配时如果i位置跳转到了k,那么k之后的任意数k‘都满足k‘>i/2,那么在i+1时,k‘+1>(i+1)/2,所以如果在i位置跳转到了k,在i+1位置继续从k+1位置即可.

技术分享
#include <cstdio>

const int mod=1e9+7;
const int maxn=1e6+5;
int ans;
char c[maxn];
int fail[maxn],cnt[maxn];

void kmp(){
    int j=0;
    fail[1]=0,cnt[1]=1;
    for(int i=2;c[i];i++){
        while(j&&c[j+1]!=c[i]) j=fail[j];
        if(c[i]==c[j+1]) j++;
        fail[i]=j;
        cnt[i]=cnt[j]+1;
    }
    j=0;ans=1;
    for(int i=2;c[i];i++){
        while(j&&c[j+1]!=c[i]) j=fail[j];
        if(c[i]==c[j+1]) j++;
        while((j<<1)>i) j=fail[j];
        ans=((long long)ans*(long long)(cnt[j]+1))%mod;
    }
}


int main()
{
    int n;
    scanf("%d",&n);
    while(n--){
        scanf("%s",c+1);
        kmp();
        printf("%d\n",ans);
    }
    return 0;
}
View Code

 

BZOJ_3670_[NOI2014]_动物园(kmp)

标签:

原文地址:http://www.cnblogs.com/Sunnie69/p/5490178.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!