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;
}

 

posted @ 2013-10-03 17:32  冰鸮  阅读(380)  评论(0编辑  收藏  举报