hdu4333 Revolving Digits 扩展kmp

Posted 天道酬勤007

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了hdu4333 Revolving Digits 扩展kmp相关的知识,希望对你有一定的参考价值。

/**
参考:http://blog.csdn.net/acdreamers/article/details/8313828
参考:http://www.61mon.com/index.php/archives/186/

题目:hdu4333 Revolving Digits
链接:http://acm.hdu.edu.cn/showproblem.php?pid=4333
题意:
给定一个数字(不含前导0),它的最后一个数字放到最前面形成一个新的数字,然后对新的数字继续处理。
问有多少种不同的数字并原数字小,等于,大于。(注意是不同的数字,注意不是字典序大小,就是比数字大小)
如果新数字有前导0,那么去掉0.显然该数字大小小于原数字。
思路:
在原数字后面连接原数字得到串t。那么i在[0,m-1],从i开始长度为m的数字就是可以转化的数字。 如果原数字有循环节,那么
只需要计算一个最小循环节长度的结果。(通过kmp找一个字符串的最小循环节。)

定义extend[i]表示t串从i开始的和原数字的最长公共前缀。
[i,i+m-1]和原数字的比较:
如果t[i]==‘0‘; 那么小于。
如果extend[i]>=m;那么等于。
如果extend[i]<m;如果t[i+extend[i]]>p[extend[i]] 那么大于。
否则小于。

Next[i]: T[i]...T[m - 1]与 T 的最长相同前缀长度;

extend[i]: S[i]...S[n - 1]与 T 的最长相同前缀长度。


*/
#include <cstdio>
#include <cstring>
#include <algorithm>
#include<set>
#include <iostream>
#include <vector>
using namespace std;
const int N = 2e5+10000;
int extend[N*2], f[N], Next[N];///不可以用next[N],会编译错误。
char t[N*2], p[N];
void GetNext(char *T,int* next)
{
    int a=0;
    int Tlen=strlen(T);
    next[0]=Tlen;
    while(a<Tlen-1&&T[a]==T[a+1]) a++;
    next[1]=a;
    a=1;
    for(int k=2;k<Tlen;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<Tlen&&T[k+j]==T[j]) j++;
            next[k]=j;
            a=k;
        }
        else next[k]=L;
    }
}

void GetExtend(char *S,char *T,int* next,int* extend)
{
    int a=0;
    GetNext(T,next);
    int Slen=strlen(S);
    int Tlen=strlen(T);
    int MinLen=Slen<Tlen? Slen:Tlen;
    while(a<MinLen&&S[a]==T[a]) a++;
    extend[0]=a;
    a=0;
    for(int k=1;k<Slen;k++)
    {
        int p=a+extend[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++;
            extend[k]=j;
            a=k;
        }
        else extend[k]=L;
    }
}

void getFail(char* P,int* f)
{
    int m = strlen(P);
    f[0] = f[1] = 0;
    for(int i = 1; i < m; i++){
        int j = f[i];
        while(j&&P[i]!=P[j]) j = f[j];
        f[i+1] = (P[i]==P[j])?j+1:0;
    }
}
int main()
{
    //freopen("in.txt","r",stdin);
    int T;
    int cas = 1;
    cin>>T;
    while(T--){
        scanf("%s",p);
        memset(extend, 0, sizeof extend);
        int m = strlen(p);
        for(int i = 0; i < m*2; i++){
            t[i] = p[i%m];
        }
        t[2*m] = \0;
        GetExtend(t,p,Next,extend);
        getFail(p,f);
        int stop = m;
        if(f[m]!=0&&m%(m-f[m])==0){
            stop = m-f[m];
        }
        int equ, big, small;
        equ = big = small = 0;
        for(int i = 0; i < m&&i<stop; i++){
            if(t[i]==0){
                small++; continue;
            }
            if(extend[i]>=m){
                equ++;
            }else
            {
                if(t[i+extend[i]]>p[extend[i]]) big++;
                else small++;
            }
        }
        printf("Case %d: %d %d %d\n",cas++,small,equ,big);
    }
    return 0;
}

 

以上是关于hdu4333 Revolving Digits 扩展kmp的主要内容,如果未能解决你的问题,请参考以下文章

扩展KMP,附上例题(HDU - 4333 Revolving Digits)

[xjoi1898] [hdu4333]Revolving Digits

Revolving Digits(hdu 4333)

HDU 4333 Revolving Digits

扩展kmp+最小循环节HDU 4333 Revolving Digits

HDU 4333 Revolving Digits [扩展KMP]学习笔记