HDU 4333 Revolving Digits (扩展KMP)

题意:给你一个数,每次把这个数尾巴上的一个数字放到前面来,问如此循环一遍形成的新的(不重复)数字中,大于,等于,小于原数字的数各有多少个。

比如样例:341->134->413->341,小于、等于、大于的各有1个。

这个串后面接上它本身,作为主串,原串作为模式串。显然这题就是要求出主串每个后缀与模式串的最长公共前缀,直接套扩展KMP模板即可。

因为形成的新的数字必须不重复,因此还需要用KMP的next函数求一下最短循环节。

#include <cstdio>

#include <cstdlib>

#include <cstring>

#include <algorithm>



using namespace std;



const int MAXN = 2001000;



int next[MAXN],extand[MAXN];

char S[MAXN],T[MAXN];

int nextval[MAXN];

int len;



void KMPgetNext(char s[],int next[])

{

    int length=len;

    int i=0,j=-1;

    next[0]=-1;

    while(i<length)

    {

        if(j==-1||s[i]==s[j])

        {

            ++i;

            ++j;

            next[i]=j;

        }

        else

            j=next[j];

    }

    return;

}



void GetNext(const char *T)

{

    len=strlen(T);

    int a=0;

    next[0]=len;

    while(a<len-1 && T[a]==T[a+1]) a++;

    next[1]=a;

    a=1;

    for(int k=2; k<len; k++)

    {

        int p=a+next[a]-1,L=next[k-a];

        if( (k-1)+L >= p)

        {

            int j = (p-k+1)>0 ? (p-k+1) : 0;

            while(k+j<len && T[k+j]==T[j]) j++;

            next[k]=j;

            a=k;

        }

        else

            next[k]=L;

    }

}



void GetExtand(const char *S,const char *T)

{

    GetNext(T);

    int slen=strlen(S),tlen=strlen(T),a=0;

    int MinLen = slen < tlen ? slen : tlen;

    while(a<MinLen && S[a]==T[a]) a++;

    extand[0]=a;

    a=0;

    for(int k=1; k<slen; k++)

    {

        int p=a+extand[a]-1, L=next[k-a];

        if( (k-1)+L >= p)

        {

            int j= (p-k+1) > 0 ? (p-k+1) : 0;

            while(k+j<slen && j<tlen && S[k+j]==T[j]) j++;

            extand[k]=j;

            a=k;

        }

        else

            extand[k]=L;

    }

}



int main()

{

    int casN, cas = 0;

    scanf( "%d", &casN );

    while ( casN-- )

    {

        scanf( "%s", T );

        strcpy( S, T );

        strcat( S, T );

        GetExtand( S, T );

        KMPgetNext( T, nextval );



        int subL = ( len % ( len - nextval[len]) ) ? len : ( len - nextval[len] );

        //printf("%d\n", subL );

        int L = 0, E = 0, G = 0;

        for ( int i = 0; i < subL; ++i )

        {

            if ( extand[i] >= len ) ++E;

            else if ( S[ extand[i] ] > S[ i + extand[i] ] ) ++L;

            else if ( S[ extand[i] ] < S[ i + extand[i] ] ) ++G;

        }



        printf("Case %d: %d %d %d\n", ++cas, L, E, G );

    }

    return 0;

}

 

你可能感兴趣的:(git)