Revolving Digits HDU - 4333 (扩展KMP)
Revolving Digits
题意:给一串数字,每次可以把最后一个移到最前面形成一个新的数字,问所有的数字中有多少比原数大、小、相等。
原数字为s,长度为len,那么一共形成len数字。
令t=s+s(连接),接下来利用扩展KMP找到t[i]对应的extend[i],然后去和s分三种情况比较。
需要注意的是如果s串是一个循环的串,那么要减去重复的数字,这里用到可KMP,len-nex[len]是循环节的长度。
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int maxn=200010; 4 char s[maxn],t[maxn]; 5 int nex[maxn],ex[maxn]; 6 int lens,lent; 7 int f[maxn]; 8 void getnex(char* t){ 9 nex[0]=lent; 10 int a=0,p=0; 11 for(int i=1;i<lent;i++){ 12 if(i>=p||i+nex[i-a]>=p){ 13 if(i>=p) p=i; 14 while(p<lent&&t[p]==t[p-i]) p++; 15 nex[i]=p-i; 16 a=i; 17 }else{ 18 nex[i]=nex[i-a]; 19 } 20 } 21 } 22 23 void exkmp(char* s,char* t){ 24 int a=0,p=0; 25 getnex(t); 26 for(int i=0;i<lens;i++){ 27 if(i>=p||i+nex[i-a]>=p){ 28 if(i>=p) p=i; 29 while(i<lens&&p-i<lent&&t[p-i]==s[p]) p++; 30 ex[i]=p-i; 31 a=i; 32 }else { 33 ex[i]=nex[i-a]; 34 } 35 } 36 } 37 void getf(char* t){ 38 f[0]=f[1]=0; 39 for(int i=1;i<lent;i++){ 40 int j=f[i]; 41 while(j&&t[i]!=t[j]) j=f[j]; 42 f[i+1]=t[i]==t[j]?j+1:0; 43 } 44 } 45 int main(){ 46 int T,kase=0; 47 scanf("%d",&T); 48 while(T--){ 49 scanf("%s",t); 50 lent=strlen(t); 51 strcpy(s,t); 52 strcat(s,t); 53 lens=lent*2; 54 printf("Case %d:",++kase); 55 exkmp(s,t); 56 int a=0,b=0,c=0; 57 getf(t); 58 int mod=lent-f[lent]; 59 int temp=1; 60 if(lent%mod==0) temp=lent/mod; 61 for(int i=0;i<lent;i++){ 62 if(ex[i]>=lent) b++; 63 else if(s[i+ex[i]]<t[ex[i]]) a++; 64 else if(s[i+ex[i]]>t[ex[i]]) c++; 65 } 66 printf(" %d %d %d\n",a/temp,b/temp,c/temp); 67 } 68 }