HDU 5442
题目链接:
题意:
一个字符串里,从任意起点出发顺时针或者逆时针遍历字符串得到一个新的字符串。问得到的字典序最大的字符串。
存在多个相同的字符串时,输出起点最小的;起点相同时,优先输出顺时针。
思路:
最小表示法 + KMP。
顺时针,直接用最小表示法得到答案。
逆时针,把串翻转。先用最小表示法得到最大字典序的字符串A,再用KMP得到离起点最远的点匹配A。
然后就完了。
最小表示法,O(n)。开两个指针,具体网上有证明。
KMP。有fail表示长度和序号的两种写法,注意不要搞混。
源码:
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <string>
#include <queue>
using namespace std;
const int MAXN = 20000 * 2 + 5;
char str1[MAXN], str2[MAXN];
char P[MAXN], T[MAXN];
int Minpre(char *s, int len)
{
int i, j, k;
i = 0;
j = 1;
while(i < len && j < len){
for(k = 0 ; k < len ; k++) if(s[(k + i) % len] != s[(k + j) % len]) break;
if(k == len) break;
if(s[(k + i) % len] > s[(k + j) % len]) i = k + i + 1;
else j = k + j + 1;
if(i == j) j++;
}
return min(i, j);
}
int fail[MAXN];
void failure(char *s, int len)
{
fail[0] = 0;
int j = 0;
for(int i = 1 ; i < len ; i++){
while(j && s[i] != s[j]) j = fail[j - 1];
if(s[i] == s[j]) j++;
fail[i] = j;
}
}
int KMP(char *P, char *T, int len1, int len2)
{
failure(P, len1);
int u, v;
u = v = 0;
int ans = 0;
while(v + len1 - u <= len2){
while(u && P[u] != T[v]) u = fail[u - 1];
if(P[u] == T[v]) u++;
if(u == len1){
u = fail[u - 1];
ans = v;
}
v++;
}
return ans;
}
int main()
{
// freopen("1006.in", "r", stdin);
int t;
scanf("%d", &t);
while(t--){
int n;
scanf("%d", &n);
scanf("%s", str1);
// printf("str1 = %s\n", str1);
for(int i = 0 ; i < n ; i++)
str1[i] = (25 - str1[i] + 'a') + 'a';
int ans1 = Minpre(str1, n);
for(int i = 0 ; i < n ; i++)
str2[i] = str1[n - i - 1];
str2[n] = '\0';
int ans2 = Minpre(str2, n);
for(int i = 0 ; i < n ; i++)
P[i] = str2[(i + ans2) % n], T[i] = T[i + n] = str2[i];
P[n] = '\0', T[n * 2] = '\0';
int temp = KMP(P, T, n, n * 2 - 1);
// printf("str1 = %s, str2 = %s\n", str1, str2);
// printf("P = %s, T = %s\n", P, T);
// printf("temp = %d", temp);
temp -= n - 1;
// if(temp < n && temp > ans2) ans2 = temp;
ans2 = n - 1 - temp;
// printf("ans1 = %d, ans2 = %d\n", ans1, ans2);
int flag = 0;
for(int i = 0 ; i < n ; i++){
int t1 = (i + ans1) % n;
int t2 = ((ans2 - i) % n + n ) % n;
// printf("t1 = %d, t2 = %d, str1[t1] = %c, str2[t2] = %c\n", t1, t2, str1[t1], str1[t2]);
if(str1[t1] > str1[t2]){
flag = -1; break;
}
else if(str1[t1] < str1[t2]){
flag = 1; break;
}
}
ans1++, ans2++;
// printf("ans1 = %d, ans2 = %d\n", ans1, ans2);
if(flag == 1){
printf("%d 0\n", ans1);
}
else if(flag == -1){
printf("%d 1\n", ans2);
}
else{
if(ans1 <= ans2)
printf("%d 0\n", ans1);
else
printf("%d 1\n", ans2);
}
}
return 0;
}