zoukankan      html  css  js  c++  java
  • POJ

    Given a sequence, {A1A2, ..., An} which is guaranteed AA2, ..., An,  you are to cut it into three sub-sequences and reverse them separately to form a new one which is the smallest possible sequence in alphabet order.

    The alphabet order is defined as follows: for two sequence {A1A2, ..., An} and {B1B2, ..., Bn}, we say {A1A2, ..., An} is smaller than {B1B2, ..., Bn} if and only if there exists such i ( 1 ≤ i ≤ n) so that we have Ai < Bi and Aj = Bj for each j < i.

    Input

    The first line contains n. (n ≤ 200000)

    The following n lines contain the sequence.

    Output

    output n lines which is the smallest possible sequence obtained.

    Sample Input

    5
    10
    1
    2
    3
    4
    

    Sample Output

    1
    10
    2
    4
    3

    题意:
    分成三个非空段,分别翻转,求字典序最小的方案.
    思路:
    将其翻转,找到字典序最小的后缀,要求起点在[0,n-2) 内,即可找到第一段.
    第一段去除之后,对原串翻转,并复制,找到字典序最小的,即可找到第二段和第三段.
    假设原串是 ab
    翻转复制后:b'a'b'a'
    a'b'就是最终的结果,所以这样做是正确的.
    当然要注意后缀起点位置.

    #include<iostream>
    #include<algorithm>
    #include<vector>
    #include<stack>
    #include<queue>
    #include<map>
    #include<set>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<ctime>
    
    #define fuck(x) cerr<<#x<<" = "<<x<<endl;
    #define debug(a, x) cerr<<#a<<"["<<x<<"] = "<<a[x]<<endl;
    #define ls (t<<1)
    #define rs ((t<<1)|1)
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    const int maxn = 200086;
    const int maxm = 100086;
    const int inf = 0x3f3f3f3f;
    const ll Inf = 999999999999999999;
    const int mod = 1000000007;
    const double eps = 1e-6;
    const double pi = acos(-1);
    
    int s[maxn];
    int len, Rank[maxn], sa[maxn], tlen, tmp[maxn];
    
    bool compare_sa(int i, int j) {
        if (Rank[i] != Rank[j]) { return Rank[i] < Rank[j]; }
        //如果以i开始,长度为k的字符串的长度,已经超出了字符串尾,那么就赋值为-1
        //这是因为,在前面所有数据相同的情况下,字符串短的字典序小.
        int ri = i + tlen <= len ? Rank[i + tlen] : -inf;
        int rj = j + tlen <= len ? Rank[j + tlen] : -inf;
        return ri < rj;
    }
    
    void construct_sa() {
        //初始的RANK为字符的ASCII码
        for (int i = 0; i <= len; i++) {
            sa[i] = i;
            Rank[i] = i < len ? s[i] : -inf;
        }
        for (tlen = 1; tlen <= len; tlen *= 2) {
            sort(sa, sa + len + 1, compare_sa);
            tmp[sa[0]] = 0;
            //全新版本的RANK,tmp用来计算新的rank
            //将字典序最小的后缀rank计为0
            //sa之中表示的后缀都是有序的,所以将下一个后缀与前一个后缀比较,如果大于前一个后缀,rank就比前一个加一.
            //否则就和前一个相等.
            for (int i = 1; i <= len; i++) {
                tmp[sa[i]] = tmp[sa[i - 1]] + (compare_sa(sa[i - 1], sa[i]) ? 1 : 0);
            }
            for (int i = 0; i <= len; i++) {
                Rank[i] = tmp[i];
    
            }
        }
    }
    
    int height[maxn];
    
    void construct_lcp() {
    //    for(int i=0;i<=n;i++){Rank[sa[i]]=i;}
        int h = 0;
        height[0] = 0;
        for (int i = 0; i < len; i++) {//i为后缀数组起始位置
            int j = sa[Rank[i] - 1];//获取当前后缀的前一个后缀(排序后)
            if (h > 0)h--;
            for (; j + h < len && i + h < len; h++) {
                if (s[j + h] != s[i + h])break;
            }
            height[Rank[i]] = h;
        }
    }
    
    int st[maxn][20];
    
    void rmq_init() {
        for (int i = 1; i <= len; i++) {
            st[i][0] = height[i];
        }
        int l = 2;
        for (int i = 1; l <= len; i++) {
            for (int j = 1; j + l / 2 <= len; j++) {
                st[j][i] = min(st[j][i - 1], st[j + l / 2][i - 1]);
            }
            l <<= 1;
        }
    }
    
    int ask_min(int i, int j) {
        int k = int(log(j - i + 1.0) / log(2.0));
        return min(st[i][k], st[j - (1 << k) + 1][k]);
    }
    
    int lcp(int a, int b)//此处参数是,原字符串下标
    {
        a = Rank[a], b = Rank[b];
        if (a > b)
            swap(a, b);
        return ask_min(a + 1, b);
    }
    
    int solve(int l, int r) {
        int ans = 0;
        for (int i = 1; i <= len; i++) {
    //        fuck(sa[i])
            if (sa[i] >= l && sa[i] <= r) {
                ans = sa[i];
                break;
            }
        }
        return ans;
    }
    
    int num[maxn];
    
    int main() {
    //    ios::sync_with_stdio(false);
    //    freopen("in.txt", "r", stdin);
        int n;
        scanf("%d", &n);
        len = n;
        for (int i = 0; i < n; i++) {
            scanf("%d", &s[i]);
            num[i] = s[i];
        }
        reverse(s, s + n);
        construct_sa();
        int fi = solve(2, n - 1);
        fi = len - fi - 1;
        reverse(num, num + fi + 1);
    
        len = 0;
        for (int i = fi + 1; i < n; i++) {
            s[len++] = num[i];
        }
        reverse(s, s + len);
        for(int i=0;i<len;i++){
            s[i+len]=s[i];
        }len*=2;
        construct_sa();
    
        int se = solve(1, len /2-1);
    
        se = n - se - 1;
        reverse(num + fi + 1, num + se + 1);
        reverse(num + se + 1, num + n);
        for (int i = 0; i < n; i++) {
            printf("%d
    ", num[i]);
        }
        return 0;
    }
    View Code
    
    

    Sequence

     POJ - 3581

  • 相关阅读:
    欧拉公式
    isap的一些想法
    错误合集
    Hello World
    PAT (Advanced Level) Practice 1068 Find More Coins
    PAT (Advanced Level) 1087 All Roads Lead to Rome
    PAT (Advanced Level) 1075 PAT Judge
    PAT (Advanced Level) 1067 Sort with Swap(0, i)
    PAT (Advanced Level) 1017 Queueing at Bank
    PAT (Advanced Level) 1025 PAT Ranking
  • 原文地址:https://www.cnblogs.com/ZGQblogs/p/11182842.html
Copyright © 2011-2022 走看看