Revolving Digits Time Limit:1000MS Memory Limit:32768KB 64bit IO Format:%I64d & %I64u
Description
Input
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
Sample Input
1 341
Sample Output
Case 1: 1 1 1
方法:扩展KMP
思路:这个数很明显要当作字符串来处理。我们在比较两个数字的时候,首先比较第一位,相同则比较下一位,以此类推,直到不同或者全部相同,然而这个比较过程会很漫长,如果有什么办法可以直接得到两个数的最长公共前缀,那就方便多了,直接比较下一位就好了,这里,就需要使用扩展KMP算法。
扩展KMP:两个串,s和T,计算s的所有后缀与T的最长公共字串的长度。
将数的末端数字拿到首端也可以等价为将原串num复制一遍接到尾部,得到extnum,然后问题就很清楚了,只要让s=extnum,T=num,那么就可以求出所有的数字与原数字的最长公共前缀长度,然后再比较一下就可以了。
另外,还需要解决重复的问题,这个需要用到循环节的概念,如果一个串经过上述操作会产生相同的数字,那就意味着这个串中含有整数个循环节,否则在拼接的时候肯定不会产生相同的数,比如121拼接完是121121,没有循环部分,而1212拼接完是12121212,很明显12这个开始循环了,因此如果原串中含有整数个循环节,那么只需要把求出来的值除以循环节的个数即可,因为每个循环节所产生的数字一定是一样的。
#include <iostream>
#include <string.h>
#include <stdio.h>
#define MAX 400010
using namespace std;
int g,e,l;
int Next[MAX*2];
char num[MAX],extnum[MAX*2];
void getNext(char *s,int *next)
{
int nn = strlen(s);
next[0] = nn;
int p = 0;
while (p+1 < nn && s[p] == s[p+1])
p++;
next[1] = p;
int k = 1, L;
for (int i = 2; i < nn; i++)
{
p = k + next[k] - 1;
L = next[i - k];
if (i + L <= p) next[i] = L;
else
{
int j = p - i + 1;
if (j < 0) j = 0;
while (i + j < nn && s[i + j] == s[j])
j++;
next[i] = j;
k = i;
}
}
/* for (int i=0;i<nn;i++){
cout<< next[i] <<" ";
}cout<<endl;
*/
}
void getExtend(char *s,char *T,int *extend,int *next)
{
int nn = strlen(s) ;
getNext(s,next);
int p = 0;
while (p < nn && s[p] == T[p])
p++;
extend[0] = p;
//extend[1] = p;
int k = 0, L;
for (int i = 1; i < nn; i++)
{
p = k + extend[k] - 1;
L = next[i - k];
if (i + L <= p) extend[i] = L;
else
{
int j = p - i + 1;
if (j < 0) j = 0;
while (i + j < nn && s[i + j] == T[j])
j++;
extend[i] = j;
k = i;
}
}
}
void getres()
{
int extlen=strlen(extnum);
int len=extlen/2;
for(int i=0;i<len;i++)
{
if(Next[i]>=len)
e++;
else
{
if(extnum[i+Next[i]]<num[Next[i]])
l++;
else
g++;
}
}
}
int getFail(char *p)
{
int f[MAX];
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]?1+j:0;
}
int len=strlen(p);
return len-f[len];
}
void output(int cas,int len,int loop)
{
int tol=1;
if(len%loop==0)
tol=len/loop;
l/=tol;
g/=tol;
e/=tol;
printf("Case %d: %d %d %d\n",cas,l,e,g);
}
void show(int len)
{
for(int i=0;i<len;i++)
{
printf("%d ",num[i]);
}
printf("\n");
}
void init()
{
int len=strlen(num);
//getNext(num,next);
strcpy(extnum,num);
for(int i=0; i<len; i++)
extnum[i+len]=num[i];
extnum[len*2]='\0';
getNext(extnum,Next);
//getExtend(extnum,extnum,ext,next);
}
int main()
{
int t,cas,loop,len;
scanf("%d",&t);
cas=0;
while(t--)
{
g=e=l=0;
scanf("%s",num);
len=strlen(num);
loop=getFail(num);
init();
//show(next,strlen(extnum));
getres();
//printf("loop=%d\n",loop);
output(++cas,len,loop);
}
return 0;
}