题目链接:hdu 5442 Favorite Donut
正序逆序分别做一遍最小表示法,但是因为逆序求出最小表示法下标对应的是为最大值,所以我们用kmp求出循环节长度,然后用下标取模即可。
#include <cstdio> #include <cstring> #include <vector> #include <queue> #include <string> #include <iostream> #include <algorithm> using namespace std; const int maxn = 20005; int N, fail[maxn]; char S[maxn], T[maxn], A[maxn], B[maxn]; int miniexpress (char* s, int n) { int p = 0, q = 1; while (p < n && q < n) { int i; for (i = 0; i < n; i++) if (s[(p+i)%n] != s[(q+i)%n]) break; if (s[(p+i)%n] < s[(q+i)%n]) p = p + i + 1; else q = q + i + 1; if (p == q) q = p + 1; } return min(p, q); } 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 getFail (char* str, int n) { int p = fail[0] = fail[1] = 0; for (int i = 2; i <= n; i++) { while (p && str[p+1] != str[i]) p = fail[p]; if (str[p+1] == str[i]) p++; fail[i] = p; } } int solve (char* s, int n) { strcpy(T+1, s); getFail(T, n); if (n % (n - fail[n])) return n; else return n - fail[n]; } int main () { int cas; scanf("%d", &cas); while (cas--) { scanf("%d%s", &N, S); int k = solve(S, N); int a = miniexpress(S, N); get(A, S, a, N); reverse(S, S + N); int b = miniexpress(S, N); get(B, S, b, N); // printf("%d %d!\n", a, N-b-1); //printf("%s %s!\n", A, B); 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; }