zoukankan      html  css  js  c++  java
  • HDU 4333 Revolving Digits [扩展KMP]【学习笔记】

    题意:给一个数字,每一次把它的最后一位拿到最前面,一直那样下去,分别求形成的数字小于,等于和大于原来数的个数。


    SAM乱搞失败

    当然要先变SS了

    然后考虑每个后缀前长为n个字符,把它跟S比较就行了

    如果用后缀家族的话复杂度要加上log,本题会TLE吧

    一个串S的每个后缀与另一个串T的最长公共前缀可以用扩展KMP!复杂度O(n+m)

    课件吧 

    从1开始写真不容易以后再也不从1开始了,判断位置好麻烦好容易错

    next[i]=LCP(T[i,m],T)

    extend[i]=LCP(S[i,n],T)

    主要思想就是求i时记录p=max{a+extend[a]-1},1<=a<i 也就是当前最远匹配到哪里,这么做是为了以后直接利用next的信息

    S[a,a+extend[a]-1]--->T[1,extend[a]-1]是一样的

    那么从i开始的后缀的前一部分是和T[i-a+1..]相同的,就不用比较了因为已经有L=next[i-a+1]了

    如果i+L-1<p,extend[i]=L

    否则从s[p+1]和t[p-i+1+1]开始暴力往后匹配,并更新a

    注意:本题要求不相同的数字,出现相同数字说明有循环节,KMP求一下看看有没有可以整除的循环节

    #include <cstdio>
    #include <cstring>
    using namespace std;
    const int N=2e6+5;
    inline int read(){
        char c=getchar();int x=0,f=1;
        while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0'; c=getchar();}
        return x*f;
    }
    inline int min(int a,int b){return a<b?a:b;}
    inline int max(int a,int b){return a>b?a:b;}
    int n,m;
    int next[N],extend[N];
    char s[N],t[N];
    void getNext(char s[],int n){
        //printf("getNext %d
    ",n);
        //for(int i=1;i<=n;i++) printf("%c",s[i]);
    
        next[1]=n;
        int a=1;
        while(a<n&&s[a]==s[a+1]) a++;
        next[2]=a-1;
        a=2;
        for(int i=3;i<=n;i++){
            int p=a+next[a]-1,L=next[i-a+1];
            if(i+L-1<p) next[i]=L;
            else{
                int j=max(p-i+1,0);//!!
                while(i+j<=n&&s[i+j]==s[j+1]) j++;
                next[i]=j;a=i;
            }
        }
        //for(int i=1;i<=n;i++) printf("next %d %d
    ",i,next[i]);
    }    
    void getExtend(char s[],char t[]){
        //printf("getExtend %d
    ",n);
        //for(int i=1;i<=n;i++) printf("%c",s[i]);puts("");
        getNext(t,m);
        int mn=min(n,m),a=1;
        while(a<=mn&&s[a]==t[a]) a++;
        extend[1]=a-1;
        a=1;
        for(int i=2;i<=n;i++){
            int p=a+extend[a]-1,L=next[i-a+1];
            if(i+L-1<p) extend[i]=L;
            else{
                int j=max(p-i+1,0);
                while(i+j<=n&&s[i+j]==t[j+1]) j++;
                extend[i]=j;
                a=i;
            }
        }
        //for(int i=1;i<=n;i++) printf("extend %d %d
    ",i,extend[i]);
    }
    int fail[N];
    void getFail(char s[],int n){
        fail[1]=0;
        for(int i=2;i<=n;i++){
            int j=fail[i-1];
            while(j&&s[j+1]!=s[i]) j=fail[j];
            fail[i]=s[j+1]==s[i]?j+1:0;
        }
    }
    int L,E,G;
    void solve(){
        getExtend(s,t);
        L=E=G=0;
        for(int i=1;i<=m;i++){
            int lcp=extend[i];
            if(lcp>=m) E++;
            else if(t[1+lcp]<s[i+lcp]) G++;
            else L++;
        }
    //for(int i=1;i<=n;i++) printf("hi %d %d %d
    ",i,next[i],extend[i]);
        getFail(t,m);
        int _=m%(m-fail[m])==0?m/(m-fail[m]):1;
        L/=_;E/=_;G/=_;
    }
    
    int main(){
        freopen("in","r",stdin);
        int T=read(),cas=0;
        while(T--){
            scanf("%s",s+1);
            n=m=strlen(s+1);
            for(int i=1;i<=n;i++) s[i+n]=t[i]=s[i];
            n<<=1;
            solve();
            printf("Case %d: %d %d %d
    ",++cas,L,E,G);
        }
    }
  • 相关阅读:
    python 获取当前时间
    PHP基础
    python 编码
    系统分区表 MBR GPT
    python mysql like查询的写法
    JSP JavaBean
    jsp MVC
    python 正则例子
    Java版A星算法
    linux 部署subversion独立服务器
  • 原文地址:https://www.cnblogs.com/candy99/p/6395066.html
Copyright © 2011-2022 走看看