大二训练第一周 C - Revolving Digits &&hdu 4333 扩展kmp

C - Revolving Digits
Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u

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^100000.暴力肯定会T。因为知道是扩展kmp问题,所以就去学习了下扩展kmp。
扩展kmp中有2个数组suffix[i]表示x串及原串x[i...x.len-1]与x[0....m-1]的最长公共前缀,就是x串的第i个子串与原串的最长公共前缀。extend[i]表示匹配串y中y[i....y.len-1]与x[0....m-1]的最长公共前缀。
我们比较新的子串与原来子串的时候如果知道他们的公共前缀,那么只要比较第一个不一样的字母就可以判断大小了。然后我们要去重,如果原来的数是存在最小循环节的,那么在匹配的过程中一定会出现循环次数个相同的数,所以把得到的答案除去它的最短循环节就好了。
//信心满满的盲打模板结果漏了一个条件,wa一整版,debug一天太弱了(逃
ACcode:

#pragma warning(disable:4786)//使命名长度不受限制
#pragma comment(linker, "/STACK:102400000,102400000")//手工开栈
#include <map>
#include <set>
#include <queue>
#include <cmath>
#include <stack>
#include <cctype>
#include <cstdio>
#include <cstring>
#include <stdlib.h>
#include <iostream>
#include <algorithm>
#define rd(x) scanf("%d",&x)
#define rd2(x,y) scanf("%d%d",&x,&y)
#define rds(x) scanf("%s",x)
#define rdc(x) scanf("%c",&x)
#define ll long long int
#define maxn 1000010
#define mod 1000000007
#define INF 0x3f3f3f3f //int 最大值
#define FOR(i,f_start,f_end) for(int i=f_start;i<=f_end;++i)
#define MT(x,i) memset(x,i,sizeof(x))
#define PI  acos(-1.0)
#define E  exp(1)
using namespace std;
int loop,n,cnt=1,m,lop;
char x[maxn];
char y[maxn<<1];
int suffix[maxn];
int mysuffix[maxn<<1];
int extand[maxn<<1];
void pre_EKMP(){
    suffix[0]=m;
    int j=0;
    while(j+1<m&&x[j]==x[j+1])j++;
    suffix[1]=j;int k=1;
    FOR(i,2,m-1){
        int p=suffix[k]+k-1;
        int L=suffix[i-k];
        if(L+i<p+1)suffix[i]=L;
        else{
            j=max(0,p-i+1);
            while(i+j<m&&x[i+j]==x[j])j++;
            suffix[i]=j;
            k=i;
        }
    }
}
void get_next(){
    int i,j;
    j=mysuffix[0]=-1;
    i=0;
    while(i<m){
        while(-1!=j&&x[i]!=x[j])j=mysuffix[j];
            mysuffix[++i]=++j;
    }
    if(m%(m-mysuffix[m])==0)lop=m/(m-mysuffix[m]);
    else lop=1;
}
void EKMP(){
    pre_EKMP();int j=0;
    while(j<m&&j<n&&x[j]==y[j])j++;
    extand[0]=j;int k=0;
    FOR(i,1,n-1){
        int p=extand[k]+k-1;
        int L=suffix[i-k];
        if(L+i<p+1)extand[i]=L;
        else{
            j=max(0,p-i+1);
            while(i+j<n&&j<m&&y[i+j]==x[j])j++;
            extand[i]=j;
            k=i;
        }
    }
}
void doit(){
    rds(x);m=strlen(x);
    strcpy(y,x);
    strcat(y,x);
    n=m<<1;
    //cout<<n<<'\12';
    EKMP(); get_next();
    int a,b,c;
    a=b=c=0;
    FOR(i,0,m-1)
        if(extand[i]>=m)b++;
        else{
            if(y[extand[i]+i]<x[extand[i]])a++;
            else c++;
        }
      //  cout<<lop<<'\12';
    printf("Case %d: %d %d %d\n",cnt++,a/lop,1,c/lop);
}
int main(){
    rd(loop);
    while(loop--)
        doit();
    return 0;
}
/*
4
341
1234567
435892
111111
*/


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值