• 暑假 D5 [NOI2014]动物园(KMP)


    题目描述

    给定一个长为L的字符串,求一个num数组,num[i]表示长度为i的前缀中字符串S‘的数量,其中S‘既是该前缀的前缀也是该前缀的后缀,且|S‘|*2≤i,为了方便输出,只用输出(num[i]+1)的乘积

    输入格式:

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

    输出格式:

    包含 n 行,每行描述一组测试数据的答案,答案的顺序应与输入数据的顺序保持一致。对于每组测试数据,仅需要输出一个整数,表示这组测试数据的答案对 1,000,000,007 取模的结果。输出文件中不应包含多余的空行。

    测试点编号约定

    N ≤ 5, L ≤ 50

    N ≤ 5, L ≤ 200

    N ≤ 5, L ≤ 200

    N ≤ 5, L ≤ 10,000

    N ≤ 5, L ≤ 10,000

    N ≤ 5, L ≤ 100,000

    N ≤ 5, L ≤ 200,000

    N ≤ 5, L ≤ 500,000

    N ≤ 5, L ≤ 1,000,000

    10 N ≤ 5, L ≤ 1,000,000

    题解

    暴力:求num[i]时暴力跳fail,将满足条件的计入

    优化:利用fail树,倍增往前跳。

    正解:求i位置的fail时,利用上一次的fail,转移方式与求fail数组相同,长度不满足再往前跳

    性质:从一个位置起不管跳多少次fail,对应的前缀仍等于原位置的相等长度的后缀

    对于cnt和fail的理解还值得思考

    #include<bits/stdc++.h>
    using namespace std;
    
    #define ll long long
    const int maxn=1000005;
    const int mod=1000000007;
    int T,n;
    char s[maxn];
    int fail[maxn],cnt[maxn];//cnt为fail为i的前缀的后缀等于前缀的个数
    //fail[i]指向的是(0,i-1)的最大前缀等于最大后缀的后一个点 
    int main(){
        scanf("%d",&T);
        while(T--){
            //memset(fail,0,sizeof(fail));
            //memset(cnt,0,sizeof(cnt));
            ll ans=1;
            scanf("%s",s);
            n=strlen(s);
            fail[0]=fail[1]=0;
            cnt[1]=1;//根据定义fail能指向1,所以s[0]是该前缀的后缀,所以cnt[1]=1 
            int t;
            for(int i=1;i<n;i++){
                t=fail[i];
                while(t&&s[t]!=s[i]) t=fail[t];
                if(s[i]==s[t]) t++;
                fail[i+1]=t;
                cnt[i+1]=cnt[t]+1;//递推,
            }
            //for(int i=0;i<n;i++) printf("%d ",cnt[i]);
            t=0;
            for(int i=0;i<n;i++){
                while(t&&s[i]!=s[t]) t=fail[t];//利用上一次的fail找 
                if(s[i]==s[t]) t++;
                while((t<<1)>(i+1)) t=fail[t];//判断长度,i+1就是因为t指向的是最大前缀的下一位 
                ans=ans*(ll)(cnt[t]+1)%mod;//因为cnt的定义所以这里*cnt[t]是正确,而不是cnt[i] 
            }
            printf("%lld
    ",ans);
        }
    }
    View Code
  • 相关阅读:
    完美立方数
    有进度条的圆周率计算
    用turtle库画童年的记忆哆啦A梦
    如何用Python画一朵太阳花
    2、4、pandas库修改excel文件内容,把excel格式存为csv格式,csv格式换为html
    python文件读写的读书笔记
    python画手绘图
    利用python把成绩用雷达图表示出来
    Numpy 和 Matplotlib库的学习笔记
    python 科学计算及数据可视化
  • 原文地址:https://www.cnblogs.com/sto324/p/11191357.html
Copyright © 2020-2023  润新知