Revolving Digits(扩展Kmp+最小循环节)

Posted caijiaming

tags:

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

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4333

Revolving Digits

Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 28267    Accepted Submission(s): 6363


Problem Description
One day Silence is interested in revolving the digits of a positive integer. In the revolving operation, he can put several last digits to the front of the integer. Of course, he can put all the digits to the front, so he will get the integer itself. For example, he can change 123 into 312, 231 and 123. Now he wanted to know how many different integers he can get that is less than the original integer, how many different integers he can get that is equal to the original integer and how many different integers he can get that is greater than the original integer. We will ensure that the original integer is positive and it has no leading zeros, but if we get an integer with some leading zeros by revolving the digits, we will regard the new integer as it has no leading zeros. For example, if the original integer is 104, we can get 410, 41 and 104.
 

 

Input
The first line of the input contains an integer T (1<=T<=50) which means the number of test cases.
For each test cases, there is only one line that is the original integer N. we will ensure that N is an positive integer without leading zeros and N is less than 10^100000.
 

 

Output
For each test case, please output a line which is "Case X: L E G", X means the number of the test case. And L means the number of integers is less than N that we can get by revolving digits. E means the number of integers is equal to N. G means the number of integers is greater than N.
 

 

Sample Input
1 341
 

 

Sample Output
Case 1: 1 1 1
 题意:输入一个整数,长度10^5,可以依次将第一个字符加在最后面,这样可以得到很多个整数,有前导0忽略,问你小于 等于 大于 最初始的数的不同数的
个数
思路:扩展kmp的板子题,在原串后面再接一个本身,这样用扩展kmp求出来的数组如果长度>=原串的长度,一定是相等的,不然直接判断nxt[i]+1的大小关系
但是要注意题目要求的是不同数的个数,所以要去重,每个数算过的次数也就是用kmp求出循环节的长度,自己可以手动推一下
看代码:
#include<iostream>
#include<cstring>
#include<algorithm>
#include<fstream>
#include<string>
using namespace std;
typedef long long LL;
const int maxn=1e5+50;
const LL mod=1e9+7;
int nxt[maxn<<1],extend[maxn<<1],next1[maxn<<1];
int ans1,ans2,ans3;
string s;
void cal_next()
{
    next1[0]=-1;
    int k=-1;
    int len=s.size();
    for(int i=1;i<len;i++)
    {
        while(k>-1&&s[k+1]!=s[i])
        {
            k=next1[k];
        }
        if(s[k+1]==s[i]) k++;
        next1[i]=k;
    }
}
void getnxt()
{
    nxt[0]=s.size();
    int now=0;
    while(s[now]==s[now+1]&&now+1<(int)s.size()) now++;
    nxt[1]=now;
    int p0=1;
    for(int i=2;i<(int)s.size();i++)
    {
        if(i+nxt[i-p0]<nxt[p0]+p0) nxt[i]=nxt[i-p0];
        else
        {
            now=nxt[p0]+p0-i;
            now=max(now,0);
            while(s[now]==s[i+now]&&i+now<(int)s.size()) now++;
            nxt[i]=now;
            p0=i;
        }
    }
}
void exkmp()
{
    getnxt();
    int len=s.size();
    for(int i=0;i<len/2;i++)
    {
        int p=nxt[i];
        if(p>=len/2) ans2++;
        else if(s[i+p]>s[p]) ans3++;
        else ans1++;
    }
}
int main()
{
    int T;scanf("%d",&T);
    int ca=1;
    while(T--)
    {
        ans1=ans2=ans3=0;
        memset(nxt,0,sizeof(nxt));
        memset(extend,0,sizeof(extend));
        memset(next1,0,sizeof(next1));
        cin>>s;
        cal_next();
        int len=s.size();
        int xunh=1;
        if(len%(len-next1[len-1]-1)==0) xunh=len/(len-next1[len-1]-1);
//        cout<<"xunh:"<<xunh<<endl;
        s+=s;
        exkmp();
        printf("Case %d: %d %d %d
",ca++,ans1/xunh,1,ans3/xunh);
    }
    return 0;
}

 

以上是关于Revolving Digits(扩展Kmp+最小循环节)的主要内容,如果未能解决你的问题,请参考以下文章

hdu4333 Revolving Digits 扩展kmp

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

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

HDU 4333 Revolving Digits

KMA & ex_KMP---Revolving Digits

HDOJ4333 Revolving Digits