• BZOJ 3670: [Noi2014]动物园 [KMP]


    求这玩意:

    对于字符串S的前i个字符构成的子串,既是它的后缀同时又是它的前缀,并且该后缀与该前缀不重叠,将这种字符串的数量记作num[i]

    1,000,000,007取模的结果

    n≤5,L≤1,000,000


    发现$num[i]$有和$fail[i]$类似的递增性质,$num[i]<num[i-1]+1$

    然后$KMP$之后$fail$递推出$sum[i]$为$i$的$fail$祖先有几个

    再类似求$fail$的过程求一遍$num$,只是多了判断$2*j le i$,用$sum[j]$更新答案就行了

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    #include <bitset>
    using namespace std;
    typedef long long ll;
    const int N=1e6+5,MOD=1e9+7;
    int n;
    char s[N];
    int fail[N],sum[N];
    void KMP(){
        fail[1]=0;
        for(int i=2;i<=n;i++){
            int j=fail[i-1];
            while(j&&s[i]!=s[j+1]) j=fail[j];
            fail[i]=s[i]==s[j+1]?j+1:0;
        }
        sum[0]=0;
        for(int i=1;i<=n;i++) sum[i]=sum[fail[i]]+1;
        //for(int i=1;i<=n;i++) printf("hi %d %d %d
    ",i,fail[i],sum[i]);
        int j=0;
        ll ans=1;
        for(int i=2;i<=n;i++){
            while(j&&s[i]!=s[j+1]) j=fail[j];
            if(s[i]==s[j+1]) j++;
            while((j<<1)>i) j=fail[j];//printf("j %d
    ",j);
            ans=ans*(sum[j]+1)%MOD;
        }
        printf("%lld
    ",ans);
    }
    int main(){
        freopen("in","r",stdin);
        int T;scanf("%d",&T);
        while(T--){
            scanf("%s",s+1);
            n=strlen(s+1);
            KMP();
        }
    }
  • 相关阅读:
    redis导入导出工具redisdump,centos7安装使用
    mysql 锁表情况,处理笔记
    python语言
    pythonhello world
    常用单词
    Django课堂笔记 1
    JS之随机点名系统
    js之简易计算器
    JS之放大镜效果
    SQLServer索引漫谈
  • 原文地址:https://www.cnblogs.com/candy99/p/6416804.html
Copyright © 2020-2023  润新知