Revolving Digits
Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 1140 Accepted Submission(s): 332
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
Sample Output
题目大意:给你一个数,不过需要用串来处理。循环移位一直移到尾变成头,问有多少个不同的数小于第一个数,同理求等于大于的个数。
解题思路:当时正在搞最大最小表示法,然后看到这个题目就直接想到那里去了。不过最大最小表示却只是在里面找一个最小的返回下标,只是两个指针在指。下来之后看了题解,是用扩展KMP做的。扩展KMP能求出一个串所有后缀串(即s[i...len])和模式串的最长公共前缀。之前看了一点但是学的不牢,所以题目也没写出来。想到扩展KMP很简单了只要将这个串复制一遍,求出该串每个后缀与其本身的最长公共前缀即可,当公共前缀>=len/num时,显然相等,否则只要比较下一位就能确定这个串与原串的大小关系。然后num肯定是用KMP最小循环节给出。
题目地址:Revolving Digits
AC代码:
/*
理解扩展KMP
一个例子 (a a c a d e f g a a c a) *2
extend 24 1 0 1 0 0 0 0 4 1 0 2
entend[8]=4; 算entend[9],先从i开始最多能有多少重合的,再与extend[i-k]比较
*/
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstdio>
#define MAXN 1000005
using namespace std;
int next[MAXN],extend[MAXN],len1,len2;
char p[MAXN],s[MAXN*2];
void getnext()
{
int i,j;
next[0]=0,next[1]=0;
for(i=1;i<len1;i++)
{
j=next[i];
while(j&&p[i]!=p[j])
j=next[j];
if(p[i]==p[j])
next[i+1]=j+1;
else
next[i+1]=0;
}
}
void getextend()
{
int i=1,k=0;
extend[0]=len2;
while(k+1<len2&&s[k]==s[k+1]) k++;
extend[1]=k;
k=1;
for(i=2;i<len1;i++)
{ //只需要求到原串/num即可
int p=k+extend[k]-i; //从i可以延伸的最长的长度
if(p<0) p=0;
extend[i]=p;
if(extend[i-k]<p) extend[i]=extend[i-k];
//从i-k点有多少公共前缀
while(i+extend[i]<len2&&s[extend[i]]==s[i+extend[i]])
extend[i]++;
if(i+extend[i]>k+extend[k])
k=i;
}
}
int main()
{
int T,cas,i;
scanf("%d",&T);
for(cas=1;cas<=T;cas++)
{
scanf("%s",p);
len1=strlen(p),len2=len1*2;
strcpy(s,p);
strcat(s,p);
s[len2]='\0';
int cnt1=0,cnt2=0,cnt3=0; //分别对应小于等于大于的个数
getnext();
getextend();
/*for(i=0;i<len1;i++)
cout<<extend[i]<<" ";
cout<<endl;*/
int num=1;
if(len1%(len1-next[len1])==0) num=len1/(len1-next[len1]); //num是指循环的次数
len2=len2/num,len1=len1/num;
for(int i=0;i<len1;i++)
{
if(extend[i]>=len1)cnt2++;
else
{
if(s[i+extend[i]]<p[extend[i]])
cnt1++;
else cnt3++;
}
}
printf("Case %d: %d %d %d\n",cas,cnt1,cnt2,cnt3);
}
return 0;
}