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

  • 相关阅读:
    hadoop
    常用安装
    rdd相关
    spark安装
    psutil
    scala linux终端高亮显示
    【原创】正则表达式(知识点总结)
    检测对象是否有某个属性(原型链检测和对象自身检测)
    JavaScript核心(对象+原型+函数+闭包+this+上下文堆栈+作用域链)
    JavaScript ES6迭代器指南
  • 原文地址:https://www.cnblogs.com/ZGQblogs/p/11182842.html
Copyright © 2011-2022 走看看