zoukankan      html  css  js  c++  java
  • poj3581Sequence(后缀数组)

    转载请注明出处: http://www.cnblogs.com/fraud/           ——by fraud

    Sequence
    Time Limit: 5000MS   Memory Limit: 65536K
    Case Time Limit: 2000MS

    Description

    Given a sequence, {A1, A2, ..., An} which is guaranteed A1 > A2, ..., 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 {A1, A2, ..., An} and {B1, B2, ..., Bn}, we say {A1, A2, ..., An} is smaller than {B1, B2, ..., Bn} if and only if there exists such i ( 1 ≤ in) 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
    

    Hint

    {10, 1, 2, 3, 4} -> {10, 1 | 2 | 3, 4} -> {1, 10, 2, 4, 3}

    题意:

    给出n个数,把这个数列分为三段,再把三段反转后连接在一起成为一个新串,求字典序最小的新串。

    思路:

    由于第一个数保证比其他所有数要大,在取第一段时直接取反转后的字典序最小的后缀即可。利用后缀数组即可求得。

    而后把剩下的一个字符串中分成两段,使得其字典序最小。首先我们会很容易的想到向第一段一样的方法,即取反转之后的字典序最小的后缀。

    但对于这种方法,我们很容易就能找到一组反例,即10 1 2 2 3

    按照上述的方法,我们会取得第一段为10 1,反转,变为1 10

    而后剩下的字符串为2 2 3,对于此串,反转之后为3 2 2,字典序最小的为2.整个串则变为1 10 2 3 2

    显然当我们取2 2的时候整个串的字典序才是最小的,为1 10 2 2 3。

    对于一个长度为m的串s[1]……s[m],设我们取将其分成s[1]……s[k]和s[k+1]……s[m]

    将其反转之后则为s[k]……s[1]s[m]……s[k+1],我们可以发现,这个串正是s[m]……s[k+1]s[k]……s[1]s[m]……s[k+1]s[k]……s[1]的子串,并且我们可以通过找这个串的长度大于m字典序最小的后缀从而得到答案。

    对于上例3 2 2,可变成3 2 2 3 2 2,长度大于m的字典序最小的后缀就是2 2 3 2 2。取其前一段即为所求的第二段。

    另外,本题必须为单组输入,否则会WA,这点坑了我好久。。。。。

     1 #include <iostream>
     2 #include <algorithm>
     3 #include <cstdio>
     4 using namespace std;
     5 #define MAXN 400010
     6 int n,k;
     7 int sa[MAXN],rank[MAXN],a[MAXN],b[MAXN],c[MAXN],tmp[MAXN];
     8 bool cmp(int i,int j){
     9     if(rank[i]!=rank[j])return rank[i]<rank[j];
    10     else {
    11         int ri=i+k<=n?rank[i+k]:-1e8;
    12         int rj=j+k<=n?rank[j+k]:-1e8;
    13         return ri<rj;
    14     }
    15 }
    16 void build(int len,int *s){
    17     n=len;
    18     for(int i=0;i<=n;i++)sa[i]=i,rank[i]=i<n?s[i]:-1e8;
    19     for(k=1;k<=n;k<<=1){
    20         sort(sa,sa+n+1,cmp);
    21         tmp[sa[0]]=0;
    22         for(int i=1;i<=n;i++){
    23             tmp[sa[i]]=tmp[sa[i-1]]+(cmp(sa[i-1],sa[i])?1:0);
    24         }
    25         for(int i=0;i<=n;i++)rank[i]=tmp[i];
    26     }
    27 }
    28 int main()
    29 {
    30     int N;
    31     scanf("%d",&N);
    32     //while(scanf("%d",&N)!=EOF){
    33         for(int i=0;i<N;i++)scanf("%d",a+i);
    34         for(int i=0;i<N;i++)b[i]=a[N-1-i];
    35         build(N,b);
    36         int p1;
    37         for(int i=0;i<=N;i++){
    38             p1=N-sa[i]-1;
    39             if(p1>=0&&p1+3<=n)break;
    40         }
    41         int m=N-p1-1;
    42         for(int i=0;i<m;i++)c[i]=a[i+p1+1];
    43         for(int i=0;i<m;i++)b[i]=b[i+m]=c[m-1-i];
    44         build(2*m,b);
    45         int p2;
    46         for(int i=0;i<=2*m;i++)
    47         {
    48             p2=m-sa[i]-1;
    49             if(p2>=0&&p2<=m-2)break;
    50         }
    51         p2+=p1+1;
    52         for(int i=p1;i>=0;i--)printf("%d
    ",a[i]);
    53         for(int i=p2;i>p1;i--)printf("%d
    ",a[i]);
    54         for(int i=N-1;i>p2;i--)printf("%d
    ",a[i]);
    55     //}
    56     return 0;
    57 }
    代码君
  • 相关阅读:
    Flex随笔
    Flex中实现类似Javascript的confirm box
    正则表达式
    MySQL存储过程
    cvc-complex-type.2.4.a: Invalid content was found starting with element
    Spket在Eclipse/MyEclipse下的安装和配置(图文教程)
    关于安装linux时要怎么分区的考虑的參考方式?
    BZOJ 1975 SDOI2010 魔法猪学院 A*k短路
    使用scipy进行聚类
    Android 下拉刷新上拉载入效果功能
  • 原文地址:https://www.cnblogs.com/fraud/p/4338434.html
Copyright © 2011-2022 走看看