• Luogu P2375 [NOI2014]动物园 KMP


    好,暴力能拿$50ptsspace qwq$


    暴力的思路就是一直跳$nxt[j]$,直到它的长度小于串的一半,然后开始计数,当然要接着跳$nxt[j]$

    正解:考虑没有长度要求的(不要求不重合)公共前后缀的数目,显然$ans[i]=ans[j]+1$相当于$i$比$j$是多了$i$它本身。

    所以求解时模仿$kmp$的过程,$num[i]$就是一直跳$nxt[j]$,然后直到$j<=frac{i}{2}$,$num[i]=ans[j]$

    注意,此处模仿$kmp$的原因是,能够避免跳过一些冗余的$nxt[j]$($nxt[j]$过大的情况),对于下一次匹配,上一次的$j$就是上一次的小于等于$frac{i}{2}$的最长公共前后缀的长度,如果还能匹配就直接匹配,过长了再跳一下$nxt[j]$,否则就一直跳$nxt[j]$,直到匹配。

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<cctype>
    #include<cstdlib>
    #include<vector>
    #include<queue>
    #include<map>
    #include<set>
    #define ull unsigned long long
    #define ll long long
    #define R register int
    #define pause for(R i=1;i<=10000000000;++i)
    using namespace std;
    namespace Fread {
        static char B[1<<15],*S=B,*D=B;
        #define getchar() (S==D&&(D=(S=B)+fread(B,1,1<<15,stdin),S==D)?EOF:*S++)
        inline int g() {
            R ret=0,fix=1; register char ch; while(!isdigit(ch=getchar())) fix=ch=='-'?-1:fix;
            do ret=ret*10+(ch^48); while(isdigit(ch=getchar())); return ret*fix;
        } inline bool isempty(const char& ch) {return ch<=36||ch>=127;}
        inline void gs(char* s) {register char ch; while(isempty(ch=getchar())); do *s++=ch; while(!isempty(ch=getchar()));}
    }using Fread::g; using Fread::gs;
    const int M=1000000007;
    int n,nxt[1000010],ans[1000010]; char s[1000010]; ll num=1;
    inline void PRE() { nxt[1]=0;
        for(R i=2,j=0;i<=n;++i) { 
            while(j&&s[i]!=s[j+1]) j=nxt[j];
            if(s[i]==s[j+1]) ++j; nxt[i]=j;
            ans[i]=ans[j]+1; 
        }
    }
    inline void calc() {
        for(R i=2,j=0;i<=n;++i) {
            while(j&&s[i]!=s[j+1]) j=nxt[j];
            if(s[i]==s[j+1]) ++j; 
            while(j>i/2) j=nxt[j];
            (num*=(ans[j]+1))%=M;
        }
    }
    signed main() {
    #ifdef JACK
        freopen("NOIPAK++.in","r",stdin);
    #endif
        R t=g(); for(R i=1;i<=t;++i) { memset(s,0,sizeof(s)); num=1;
            gs(s+1); n=strlen(s+1);  ans[1]=1; PRE();
    //        for(R i=2;i<=n;++i) { R lim=i/2,j=i,cnt=0;
    //            while(j) {j=nxt[j]; if(j&&j<=lim) ++cnt;}
    //            (ans*=(cnt+1))%=M; 
    //        } 
            calc();
            printf("%lld
    ",num);
        } 
    }

    2019.06.15

  • 相关阅读:
    HTML和XHTML知识总结
    理解margin-left:-100%
    git clean的用法
    vue路由传参的三种基本方式
    vertical-align属性
    纯CSS制作各种图形(多图预警)
    css伪元素:before和:after用法详解
    前端注册登录的业务流程
    Vue-cli 中为单独页面设置背景图片铺满全屏的方法
    vscode 开启对 webpack alias(文件别名) 引入的智能提示
  • 原文地址:https://www.cnblogs.com/Jackpei/p/11028492.html
Copyright © 2020-2023  润新知