题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=3374
解题思路:
题目大意:
给你一个字符串,每次将最前一个字符放到最后,直到形成一周,然后按照每个字符串出现的先后排个名次,现在要你求出字典序
最小的字符串和字典序最大的字符串为RANK几。并输出它们的出现次数,如果出现次数不只一次,那么输出RANK值较小的。
算法思想:
先用kmp求出循环节,再用最小表示法,分别求出字典序最小的字符串和字典序最大的字符串为RANK几。
最小表示法模板:
http://blog.csdn.net/piaocoder/article/details/48447193
AC代码:
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 1000005;
char str[maxn];
int Next[maxn];
void getNext(char *p){
int len = strlen(p);
int j = 0,k = -1;
Next[0] = -1;
while(j < len){
if(k==-1 || p[j]==p[k]){
j++; k++;
Next[j] = k;
}
else
k = Next[k];
}
}
int minRepresstation(char *s,bool flag = true){
int len = strlen(s);
int i = 0,j = 1,k = 0;
while(i<len && j<len && k<len){
int tmp = s[(i+k)%len]-s[(j+k)%len];
if(tmp == 0)
k++;
else{
if(flag?tmp > 0:tmp < 0)
i += k+1;
else
j += k+1;
if(i == j)
j++;
k = 0;
}
}
return min(i,j);
}
int main(){
while(~scanf("%s", str)){
int len,minlen,num;
len = strlen(str);
getNext(str);
if (len % (len-Next[len]) == 0)
minlen = len-Next[len];
else
minlen = len;
num = len / minlen;
printf("%d %d %d %d\n",minRepresstation(str)+1,num,minRepresstation(str,false)+1,num);
}
return 0;
}