您的位置:首页 > 产品设计 > UI/UE

(后缀数组)poj 3581 Sequence

2017-05-26 21:00 288 查看
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 ≤ 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

Hint

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

这个题目的描述实在是太不详细,既没给范围、数据类型,也没有对“分成三部分”给出明确的定义。

在此根据自己因为题意不明出过的错误,阐明一下:

1、数据全是不超过int范围的非负数

2、“分成三部分”每一部分都不为空

希望后来做这个题目的同学如果看到这篇文章能不再因以上原因浪费不该浪费的时间。

首先将整个数组反过来看,由于第一个数是最大的,翻转之后只需要先找到此刻最小的后缀位置,就是第一个划分的区间。该位置需满足除该区间以外至少还剩余2个数。

之后再划分余下的部分。

注意到,如果一个圆环形式为[x,y][z,q] 将其两部分分别颠倒,得到[y,x] [q,z],通过整体翻转就又可以得到[x,y][z,q]的某一旋转形式。对于这样将一个大区间划分成两个小的之后再分别翻转,也是同理的。所以,可以把余下的部分再复制一份到后面(此时第一部分的已经去掉)。进行后缀数组的计算,找在非复制得到的位置的最小的后缀(且要保证余下至少1个数),就完成了对余下区间的划分。

1 #include <iostream>
2 #include <string>
3 #include <algorithm>
4 #include <cstring>
5 #include <cstdio>
6 #include <cmath>
7 #include <queue>
8 #include <set>
9 #include <map>
10 #include <list>
11 #include <vector>
12 #include <stack>
13 #define mp make_pair
14 #define MIN(a,b) (a>b?b:a)
15 #define rank rankk
16 //#define MAX(a,b) (a>b?a:b)
17 typedef long long ll;
18 typedef unsigned long long ull;
19 const int MAX=4e5+5;
20 const int INF=2147483647;
21 const int B=1024;//桶的大小
22 const double M=4e18;
23 using namespace std;
24 const int MOD=1e9+7;
25 typedef pair<int,int> pii;
26
27 int n,k;
28 int a[MAX],rank[MAX],tmp[MAX],sa[MAX];
29 bool cmp(int i,int j)
30 {
31     if(rank[i]!=rank[j])
32         return rank[i]<rank[j];
33     else
34     {
35         int ri=i+k<=n?rank[i+k]:-1;
36         int rj=j+k<=n?rank[j+k]:-1;
37         return ri<rj;
38     }
39 }
40 void construct_sa(int n)
41 {
42     if(n<=0)
43         return;
44     for(int i=1;i<=n;i++)
45     {
46         sa[i]=i;
47         rank[i]=a[i];
48     }
49     for(k=1;k<=n;k*=2)
50     {
51         sort(sa+1,sa+n+1,cmp);
52         tmp[sa[1]]=1;
53         for(int i=2;i<=n;i++)
54         {
55                 tmp[sa[i]]=tmp[sa[i-1]]+(cmp(sa[i-1],sa[i])?1:0);
56         }
57         for(int i=1;i<=n;i++)
58             rank[i]=tmp[i];
59     }
60 }
61 int main()
62 {
63     scanf("%d",&n);
64     for(int i=1;i<=n;i++)
65         scanf("%d",&a[i]);
66     reverse(a+1,a+1+n);
67     construct_sa(n);
68     int an=INF,lo=1;
69     int p1;
70     for(int i=1;i<=n;i++)
71     {
72         if(sa[i]<=n-1&&sa[i]>=3)
73         {
74             lo=sa[i];
75             break;
76         }
77     }
78     for(int i=lo;i<=n;i++)
79         printf("%d\n",a[i]);
80     for(int i=1;i<lo;i++)
81         a[lo+i-1]=a[i];
82     construct_sa(2*lo-2);
83     an=INF;int los=1;
84     for(int i=1;i<=2*lo-2;i++)
85     {
86         if(lo-1-sa[i]>=0&&sa[i]>=2)
87         {
88             los=sa[i];break;
89         }
90     }
91     for(int i=los;i<lo;i++)
92         printf("%d\n",a[i]);
93     for(int i=1;i<los;i++)
94         printf("%d\n",a[i]);
95 }
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: