1、给一个数字字符串s,可以把它的最后一个字符放到最前面变为另一个数字,直到又变为原来的s。求这个过程中比原来的数字小的、相等的、大的数字各有多少。
例如:字符串123,变换过程:123 -> 312 -> 231 -> 123
因为:312>123, 231>123, 123=123
所以答案是:0 1 2
2、令str1=s,str2=s+s,然后str1作为子串,str2作为主串,进行扩展kmp求出str2[i...len2-1]与str1[0...len1-1]的最长公共前缀。当公共前缀==len1时,两个数相等;否则,只须比较公共前缀后的下一个字符就能判断大小了。
注意当中有重复的情况,只有当s有循环节的时候才会出现,先求出s的最小循环节,然后用s的长度除以最小循环节得到循环节的个数,将3个结果都除以循环节个数即可。
3、
#include<iostream> #include<stdio.h> #include<string.h> using namespace std; #define MaxSize 200005 int _next[MaxSize],extend[MaxSize]; //扩展kmp //next[i]:x[i...m-1]与x[0...m-1]的最长公公前缀 //extend[i]:y[i...n-1]与x[0...m-1]的最长公共前缀 void pre_EKMP(char x[],int m,int _next[]){//m长度 _next[0]=m; int j=0; while(j+1<m&&x[j]==x[j+1])j++; _next[1]=j; int k=1; for(int i=2;i<m;i++){ int p=_next[k]+k-1; int L=_next[i-k]; if(i+L<p+1)_next[i]=L; else{ j=max(0,p-i+1); while(i+j<m&&x[i+j]==x[j])j++; _next[i]=j; k=i; } } } void EKMP(char x[],int m,char y[],int n,int _next[],int extend[]){//x子串,m子串长度,y主串,n主串长度 pre_EKMP(x,m,_next); int j=0; while(j<n&&j<m&&x[j]==y[j])j++; extend[0]=j; int k=0; for(int i=1;i<n;i++){ int p=extend[k]+k-1; int L=_next[i-k]; if(i+L<p+1)extend[i]=L; else{ j=max(0,p-i+1); while(i+j<n&&j<m&&y[i+j]==x[j])j++; extend[i]=j; k=i; } } } /* 子串 :a b a b 主串 :a b a b a c next :4 0 2 0 extend:4 0 3 0 1 0 */ void GetNext(char t[]){//求next数组 int j,k,len; j=0;//从0开始,首先求_next[1] k=-1;//比较指针 _next[0]=-1;//初始值-1 len=strlen(t); while(j<len){ if(k==-1||t[j]==t[k]){//指针到头了,或者相等 ++j; ++k; _next[j]=k;//此句可由优化替代 /*优化(求匹配位置时可用) if(t[j]!=t[k])_next[j]=k; else _next[j]=_next[k]; //*/ } else k=_next[k]; } } int main(){ char str1[100005],str2[200005];//子串,主串 int i,j,len1,len2;//子串长度,主串长度 int T; int sumL,sumE,sumG; scanf("%d",&T); for(i=1;i<=T;++i){ sumL=sumE=sumG=0; scanf("%s",str1); strcpy(str2,str1); strcat(str2,str1); len1=strlen(str1); len2=strlen(str2); EKMP(str1,len1,str2,len2,_next,extend); for(j=0;j<len1;++j){ if(extend[j]==len1)++sumE; else if(str2[j+extend[j]]<str1[extend[j]])++sumL; else ++sumG; } GetNext(str1); int repetend=len1-_next[len1];//最小循环节 int numR;//循环节的个数 if(len1%repetend==0)numR=len1/repetend; else numR=1; printf("Case %d: %d %d %d ",i,sumL/numR,sumE/numR,sumG/numR); } return 0; }