zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    VMware16Pro永久激活key密钥亲测可用
    软件客户端激活码设计思路
    Android 监听外部U盘插入事件
    分享一款由python开发的全能多线程抢购神器,支持华为、京东、淘宝等商城
    android遇见Uninitialized object exists on backward branch 142解决办法
    android framework-下载Android系统源代码
    android-windowManager使用实例
    理解Android Framework
    4种常用线程池介绍
    谈一款MOBA类游戏《码神联盟》的服务端架构设计与实现 (转载)
  • 原文地址:https://www.cnblogs.com/yohaha/p/5722826.html
Copyright © 2011-2022 走看看