hdu 5442 Favorite Donut 最大表示法+kmp

题目链接

给你一个字符串, 然后把他想象成一个环。 从某一个地方断开,然后逆时针或顺时针, 都可以形成一个字符串, 求字典序最大的那种。 输出断开位置以及是顺时针还是逆时针。

如果两个一样, 输出位置靠前的一个, 如果位置也一样, 输出顺时针的那个。

显然是一个最大表示法。 麻烦的是逆时针的情况, 因为要输出位置靠前的一个。 但是逆时针求出来的是字符串反转之后靠前的, 所以应该求一遍kmp, 找出来最靠后的一个位置。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string>
using namespace std;
const int maxn = 4e4+5;
int a[maxn], b[maxn], pos[maxn], nxt[maxn], c[maxn];
int getMax(int a[], int n)
{
    int i, j, k;
    for(i = 0, j = 1; i<n&&j<n; ) {
        for(k = 0; k<n&&a[i+k]==a[j+k]; k++)
            ;
        if(k>=n)
            break;
        if(a[i+k]>a[j+k])
            j += k+1;
        else
            i += k+1;
        if(i == j)
            j++;
    }
    return i;
}
int solve(string s, int a[], int n)
{
    for(int i = 0; i < n; i++) {
        a[i] = s[i]-'a';
    }
    for(int i = n; i < 2*n-1; i++) {
        a[i] = a[i-n];
    }
    int pos = getMax(a, n);
    return pos;
}
void init_kmp(int m) {
    int i = 0, j = -1;
    nxt[0] = -1;
    while(i<m) {
        if(j == -1 || c[i] == c[j]) {
            ++i, ++j;
            nxt[i] = j;
        } else {
            j = nxt[j];
        }
    }
}
int kmp(int n)
{
    int cnt = 0;
    int i = 0, j = 0;
    while(i<2*n-1) {
        if(j == -1 || b[i] == c[j]) {
            i++, j++;
        } else {
            j = nxt[j];
        }
        if(j == n) {
            pos[cnt++] = i;
            j = nxt[j];
        }
    }
    return cnt;
}
int main()
{
    int t, n;
    string s;
    cin>>t;
    while(t--) {
        cin>>n>>s;
        int pos1 = solve(s, a, n);
        int num = 0, flag = -1;
        reverse(s.begin(), s.end());
        int pos2 = solve(s, b, n);
        int tmp1 = pos1, tmp2 = pos2;
        while(num < n) {
            if(a[pos1] > b[pos2]) {
                flag = 1;
                break;
            } else if(a[pos1] < b[pos2]) {
                flag = 0;
                break;
            } else {
                pos1++;
                pos2++;
                num++;
            }
        }
        int cnt = 0;
        for(int i = tmp2; i < tmp2+n; i++) {
            c[cnt++] = b[i];
        }
        init_kmp(n);
        cnt = kmp(n);
        tmp2 = pos[cnt-1]%n;
        if(num == n) {
            if(tmp1+1 <= n-tmp2) {
                flag = 1;
            } else {
                flag = 0;
            }
        }
        if(flag) {
            printf("%d %d
", tmp1+1, !flag);
        } else {
            printf("%d %d
", n-tmp2, !flag);
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/yohaha/p/5722826.html