/** 参考:http://blog.csdn.net/acdreamers/article/details/8313828 参考:http://www.61mon.com/index.php/archives/186/ 题目:hdu4333 Revolving Digits 链接:http://acm.hdu.edu.cn/showproblem.php?pid=4333 题意: 给定一个数字(不含前导0),它的最后一个数字放到最前面形成一个新的数字,然后对新的数字继续处理。 问有多少种不同的数字并原数字小,等于,大于。(注意是不同的数字,注意不是字典序大小,就是比数字大小) 如果新数字有前导0,那么去掉0.显然该数字大小小于原数字。 思路: 在原数字后面连接原数字得到串t。那么i在[0,m-1],从i开始长度为m的数字就是可以转化的数字。 如果原数字有循环节,那么 只需要计算一个最小循环节长度的结果。(通过kmp找一个字符串的最小循环节。) 定义extend[i]表示t串从i开始的和原数字的最长公共前缀。 [i,i+m-1]和原数字的比较: 如果t[i]==‘0‘; 那么小于。 如果extend[i]>=m;那么等于。 如果extend[i]<m;如果t[i+extend[i]]>p[extend[i]] 那么大于。 否则小于。 Next[i]: T[i]...T[m - 1]与 T 的最长相同前缀长度; extend[i]: S[i]...S[n - 1]与 T 的最长相同前缀长度。 */ #include <cstdio> #include <cstring> #include <algorithm> #include<set> #include <iostream> #include <vector> using namespace std; const int N = 2e5+10000; int extend[N*2], f[N], Next[N];///不可以用next[N],会编译错误。 char t[N*2], p[N]; void GetNext(char *T,int* next) { int a=0; int Tlen=strlen(T); next[0]=Tlen; while(a<Tlen-1&&T[a]==T[a+1]) a++; next[1]=a; a=1; for(int k=2;k<Tlen;k++) { int p=a+next[a]-1,L=next[k-a]; if((k-1)+L>=p) { int j=(p-k+1)>0? p-k+1:0; while(k+j<Tlen&&T[k+j]==T[j]) j++; next[k]=j; a=k; } else next[k]=L; } } void GetExtend(char *S,char *T,int* next,int* extend) { int a=0; GetNext(T,next); int Slen=strlen(S); int Tlen=strlen(T); int MinLen=Slen<Tlen? Slen:Tlen; while(a<MinLen&&S[a]==T[a]) a++; extend[0]=a; a=0; for(int k=1;k<Slen;k++) { int p=a+extend[a]-1,L=next[k-a]; if((k-1)+L>=p) { int j=(p-k+1)>0? p-k+1:0; while(k+j<Slen&&j<Tlen&&S[k+j]==T[j]) j++; extend[k]=j; a=k; } else extend[k]=L; } } void getFail(char* P,int* f) { 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])?j+1:0; } } int main() { //freopen("in.txt","r",stdin); int T; int cas = 1; cin>>T; while(T--){ scanf("%s",p); memset(extend, 0, sizeof extend); int m = strlen(p); for(int i = 0; i < m*2; i++){ t[i] = p[i%m]; } t[2*m] = ‘\0‘; GetExtend(t,p,Next,extend); getFail(p,f); int stop = m; if(f[m]!=0&&m%(m-f[m])==0){ stop = m-f[m]; } int equ, big, small; equ = big = small = 0; for(int i = 0; i < m&&i<stop; i++){ if(t[i]==‘0‘){ small++; continue; } if(extend[i]>=m){ equ++; }else { if(t[i+extend[i]]>p[extend[i]]) big++; else small++; } } printf("Case %d: %d %d %d\n",cas++,small,equ,big); } return 0; }
时间: 2024-10-24 20:37:54