这题要求的是字符串左移时字典序最小和最大的第几次出现,并求出现次数。考虑一会可以发现,出现次数和循环节是有关系的。
出现了几次,就是循环了几次,如果循环节是他本身,也就是无循环,那这个字符串不管怎么移,都只有一种情况。
关键就是求第几次出现,也就是最大最小的表示。顺便学习了一下。
#include<stdio.h> #include<string.h> #define maxn 1000010 int next_v[maxn],min,max; char s[maxn]; void getnext_v() { int j,k,len=strlen(s); j=0; k=-1; next_v[0]=-1; while(j<len) { if(k==-1||s[j]==s[k]) { j++; k++; next_v[j]=k; } else k=next_v[k]; } } int get_min() { int i=0,j=1,k=0,t,l=strlen(s); while(i<l&&j<l&&k<l) { t=s[(j+k)%l]-s[(i+k)%l]; if(!t) k++; else { if(t>0) j=j+k+1; else i=i+k+1; if(i==j) j++; k=0; } } return (i<j?i:j); } int get_max() { int i=0,j=1,k=0,t,l=strlen(s); while(i<l&&j<l&&k<l) { t=s[(j+k)%l]-s[(i+k)%l]; if(!t) k++; else { if(t<0) j=j+k+1; else i=i+k+1; if(i==j) j++; k=0; } } return (i<j?i:j); } void kmp() { getnext_v(); int i,j,len=strlen(s),flag=1; int fl=len-next_v[len]; if(len%fl) flag=0; min=get_min(); max=get_max(); if(flag) { printf("%d %d %d %d ",min+1,len/fl,max+1,len/fl); } else { printf("%d 1 %d 1 ",min+1,max+1); } } int main() { int i,j; while(scanf("%s",s)!=EOF) { kmp(); } }