• [bzoj3670][Noi2014]动物园


    Description

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

    \(mod\;10^9+7\)

    Input

    \(1\)行仅包含一个正整数\(n\),表示测试数据的组数。
    随后\(n\)行,每行描述一组测试数据。每组测试数据仅含有一个字符串\(S\)\(S\)的定义详见题目描述。数据保证\(S\)中仅含小写字母。输入文件中不会包含多余的空行,行末不会存在多余的空格。

    Output

    包含\(n\)行,每行描述一组测试数据的答案,答案的顺序应与输入数据的顺序保持一致。对于每组测试数据,仅需要输出一个整数,表示这组测试数据的答案\(mod\;10^9+7\)的结果。

    Sample Input

    3
    aaaaa
    ab
    abcababc
    

    Sample Output

    36
    1
    32
    

    HINT

    \(n\;\leq\;5,L\;\leq\;16\)

    Solution

    题意就是给你一个字符串\(S\)\(num[i]\)表示在前缀\(S[1...i]\)上,满足\(next[j]\;\times\;2\;\leq\;i\)\(j\)的个数(\(1\leq j\leq i\)),求\(num[i]\)

    那么,就先思考问题的简化版,在没有\(next[j]\;\times\;2\;\leq\;i\)的限制下,即不要求前后缀不重叠时,\(num'[i]=num'[next[i]]+1\)。(实现时,\(num'[\;]\)记作\(cnt[\;]\)

    现在问题就变成了,如何不用\(O(n^2)\)的算法求满足条件的\(j\)

    我们可以再用\(kmp\)的思想完成这件事,当发现现在的\(j\)不满足条件时,可以用\(next[\;]\)向前寻找满足条件的\(j\)

    这样的话,每次都是从满足\(next[j]\;\times\;2\;\leq\;i-1\)\(j\)开始寻找,避免了一些重复向前找的时间复杂度,于是就\(A\)了。此时\(num[i]=num^{'}[j]=num^{'}[next[j]]+1\)

    #include<set> 
    #include<cmath>
    #include<ctime>
    #include<queue>
    #include<stack>
    #include<cstdio>
    #include<vector> 
    #include<string>
    #include<cstring>
    #include<cstdlib>
    #include<iostream>
    #include<algorithm>
    #define N 1000002
    #define M 1000000007
    using namespace std;
    int t[N],cnt[N],next[N],n,m;
    long long ans;
    char a[N];
    inline void get_next(){
        for(int i=2,j=0;i<=m;i++){
            while(j&&a[i]!=a[j+1]) j=next[j];
            j+=(a[i]==a[j+1]);
            next[i]=j;
            cnt[i]=cnt[j]+1;
        }
    }
    inline void init(){
        scanf("%d",&n);cnt[1]=1;
        for(int l=1;l<=n;l++){
            scanf("%s",a+1);
            m=strlen(a+1);
            fill(next+1,next+1+m,0);
            get_next();ans=1;
            for(int i=2,j=0;i<=m;i++){
                while(j&&a[i]!=a[j+1]) j=next[j]; 
                if(a[i]==a[j+1]) j++;
                while(j*2>i) j=next[j];
                ans=ans*(cnt[j]+1)%M;
            }
            printf("%lld\n",ans);
        }
        
    }
    int main(){
        freopen("zoo.in","r",stdin);
        freopen("zoo.out","w",stdout);
        init();
        fclose(stdin);
        fclose(stdout);
        return 0;
    }
  • 相关阅读:
    毕业设计记录——3.5
    毕业设计记录——3.4
    毕业设计记录——3.3
    阿里云申请SSL 配置https
    毕业设计记录——3.2
    毕业设计(2.25-3.1)周工作计划
    远程连接阿里云ecs 服务器Ubuntu 16.04报错 解决
    基于springboot的ajax异步文件上传
    《需求工程-软件建模与分析之读书笔记之四》
    《需求工程-软件建模与分析之读书笔记之三》
  • 原文地址:https://www.cnblogs.com/AireenYe/p/bzoj3670.html
Copyright © 2020-2023  润新知