hdu 4333(扩展KMP)

来源:互联网 发布:西门子840d编程指令 编辑:程序博客网 时间:2024/06/07 00:41

题意:就是给你一个数字,然后把最后一个数字放到最前面去,经过几次变换后又回到原数字,问在这些数字中,比原数字小的,相等的,大的分别有多少个。比如341-->134-->413-->341,所以和原数字相比,比原数字小的有一个,相等的有一个,大的有一个。

分析:经过观察,其实就是求每一位的后缀与自身的最长公共前缀,这个显然可以用扩展kmp处理,但是开始的时候我超时了,后来在网上看到别人把这个串后面再接上本身,以它为主串,然后以自身为模板串进行扩展kmp,这样处理把时间复杂度降到了线性的,最后要注意的一个问题就是如何避免重复了,我们可以用普通的kmp求出此串的最小循环节,如果构成完整的循环,那么我们要算的就是循环节长度的情况了!


#include<stdio.h>#include<string.h>char S[201000],T[100500];int next[200500],extend[200500],len,node;void get_node(){    int i=0,j=-1;    next[0]=-1;    while(i<len)    {        if(j==-1||T[i]==T[j])        {            i++;j++;            next[i]=j;        }        else         j=next[j];    }    //最小循环节,如1212 ,最小循环节为2,即长度大于2了以后就开始重复了;     node=len-next[len];}void get_next(){    int a,p,k,j,len;    int L;    len=strlen(T);    next[0]=len;    a=0;    while(a<len-1&&T[a]==T[a+1])        a++;    next[1]=a;    a=1;    for(k=2;k<len;k++)    {        p=a+next[a]-1;        L=next[k-a];        if(k-1+L>=p)        {            j=p-k+1>0?p-k+1:0;            while(j+k<len&&T[j+k]==T[j])                j++;            next[k]=j;            a=k;        }        else            next[k]=L;    }}void get_extend(){    get_next();    int a,p,L,k,j,slen,tlen,len;    slen=strlen(S);tlen=strlen(T);    len=slen>tlen?tlen:slen;    a=0;    while(a<len&&S[a]==T[a])        a++;    extend[0]=a;    a=0;    for(k=1;k<slen;k++)    {        p=a+extend[a]-1;        L=next[k-a];        if(k-1+L>=p)        {            j=p-k+1>0?p-k+1:0;            while(j+k<slen&&j<tlen&&S[j+k]==T[j])                j++;            extend[k]=j;            a=k;        }        else            extend[k]=L;    }}void solve(){    printf("%d*",node);     int i,num1=0,num2=0,num3=0,flag;    if(len%node!=0)     node=len;    for(i=0;i<node;i++)    {        if(extend[i]>=len)         num2++;        else if(S[extend[i]]>S[i+extend[i]])  //小于原串          num1++;        else if(S[extend[i]]<S[i+extend[i]])  //大于原串          num3++;    }      printf("%d %d %d\n",num1,num2,num3);}int main(){    int t,i;    scanf("%d",&t);    getchar();    for(i=1;i<=t;i++)    {        scanf("%s",T);        strcpy(S,T);        strcat(S,T);        len=strlen(T);        get_node();        get_next();        get_extend();        printf("Case %d: ",i);        solve();    }    return 0;}


0 0
原创粉丝点击