http://acm.hdu.edu.cn/showproblem.php?pid=3374
原来这个东西叫最小表示。。。
方法:分别求一次最小表示和最大表示求出首字母位置,然后下面就比较暴力,用两次kmp求出最大串和最小串出现的次数
#define N 1000010
char 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;
}