题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=5442
解题思路:
题目大意:
有一个len长度的环,问有没有最大的长度为len的串在这个环里。
如果有的话,且只有一个,输出其开头的下标,下标从1 开始,再输出0 表示顺时针1表示逆时针
如果多个,输出开头下标最小的那个。
还有如果,就是顺时针,逆时针一样的情况,输出下标 0。
算法思想:
最小表示法模板:
http://blog.csdn.net/piaocoder/article/details/48447193
首先正序直接用最大表示法 ,可以得到最大字典序,最小下标的开头位置。
然后逆序就把串反下,用最大表示法,可以得到最大字典序,也是下标最小的开头位置,但是因为颠倒了,这里的下标是倒序的,
所以下标其实是最大的。 但是我们已经得到 最大 字典序的串了, 所以接下来把反的串重复一遍,可以用kmp找其中相同串的最大
起始位置。
然后把两个最大字典序的串比较下大小。正序大输出正序,逆序大出逆序,相等则输出标号最小的。
AC代码:
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 20005;
int n,Next[maxn];
char S[maxn],T[maxn],A[maxn],B[maxn];
int maxRepresstation(char *s){
int len = n;
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(tmp < 0)//最大表示法
i += k+1;
else
j += k+1;
if(i == j)
j++;
k = 0;
}
}
return min(i,j);
}
void get(char* t,char* s,int a,int n){
for (int i = 0; i < n; i++)
t[i] = s[(a+i)%n];
t[n] = '\0';
}
bool judge(int a,int b){
int k = strcmp(A,B);
if (k != 0)
return k > 0;
return
a <= b;
}
void getNext(char *p){
int j = 0,k = -1;
Next[0] = -1;
while(j < n){
if(k==-1 || p[j]==p[k]){
j++; k++;
Next[j] = k;
}
else
k = Next[k];
}
}
int solve (char* s){
getNext(s);
if (n % (n - Next[n]))
return n;
else
return n - Next[n];
}
int main(){
int T;
scanf("%d",&T);
while(T--) {
scanf("%d%s",&n,S);
int k = solve(S);
int a = maxRepresstation(S);
get(A,S,a,n);
reverse(S,S + n);
int b = maxRepresstation(S);
get(B,S,b,n);
a %= k;
b = (n - b - 1) % k;
if(judge(a,b))
printf("%d 0\n",a + 1);
else
printf("%d 1\n",b + 1);
}
return 0;
}