http://acm.hdu.edu.cn/showproblem.php?pid=3374
原來這個東西叫最小表示。。。
方法:分別求一次最小表示和最大表示求出首字母位置,然後下面就比較暴力,用兩次kmp求出最大串和最小串出現的次數
#define N 1000010char str[N],ss[N*2],lin[N];int p[N];int Minrp(char *s, int l){//最小表示 int i = 0, j = 1, k = 0, t; while(i < l && j < l && k < l) { t = s[(i+k) >= l ? i+k-l : i+k] - s[(j+k) >= l ? j+k-l : j+k]; if(!t) k++; else{ if(t > 0) i = i + k + 1; else j = j + k + 1; if(i == j) ++j; k = 0; } } return i;}int Maxrp(char *s, int l){//最大表示 int i = 0, j = 1, k = 0, t; while(i < l && j < l && k < l) { t = s[(i+k) >= l ? i+k-l : i+k] - s[(j+k) >= l ? j+k-l : j+k]; if(!t) k++; else{ if(t < 0) i = i + k + 1; else j = j + k + 1; if(i == j) ++j; k = 0; } } return i;}void kmp(){ int len = strlen(lin); int i,j,k; p[0] = -1; j = -1; for(i=1;i<len;i++){ while(j>=0 && lin[i] != lin[j+1])j = p[j]; if(lin[i] == lin[j+1])j++; p[i] = j; }}int kmp_(char *s){ int len = strlen(s); int n = strlen(lin); int i,j=-1; int sum = 0; for(i=0;i<len;i++){ while(j>=0 && s[i]!=lin[j+1])j = p[j]; if(s[i]==lin[j+1])j++; if(j==n-1 && i!=len-1){ sum++; j = p[j]; } } return sum;}int main(){ while(scanf("%s",str)!=EOF){ int i,j,k; int len = strlen(str); int minr = Minrp(str,len)+1; int maxr = Maxrp(str,len)+1; strcpy(ss,str); strcat(ss,str); for(k=0,i=minr-1;i<len;i++){ lin[k++] = str[i]; } for(i=0;i<minr-1;i++){ lin[k++] = str[i]; } lin[k] = '\0'; kmp(); int mint = kmp_(ss); for(k=0,i=maxr-1;i<len;i++){ lin[k++] = str[i]; } for(i=0;i<maxr-1;i++){ lin[k++] = str[i]; } lin[k] = '\0'; kmp(); int maxt = kmp_(ss); printf("%d %d %d %d\n",minr,mint,maxr,maxt); } return 0;}