Revolving Digits Time Limit:1000MS Memory Limit:32768KB 64bit IO Format:%I64d & %I64u
Description
Input
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; }