POJ3581 Sequence —— 后缀数组

题目链接:https://vjudge.net/problem/POJ-3581

 

Sequence
Time Limit: 5000MS   Memory Limit: 65536K
Total Submissions: 7754   Accepted: 1761
Case Time Limit: 2000MS

Description

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

Hint

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

Source

 

 

题意:

给出一个字符串,将其分成三段,并且将每一段翻转。求翻转过后字典序最小的一个。

 

题解:

1.分成三段,即求出两个分割点,于是分两部分进行求解。

2.第一部分:求第一段。由于求的是翻转过后字典序最小的,那么先将原字符串翻转得到逆串,然后求其后缀数组。那么排名最靠前且满足能分成三段的那个后缀,即为翻转过后的第一段。 形如:1 1 2 2 3 3 等最小值重复出现在前面的串,如果直接求其逆串的后缀数组,那么排名最靠前的是“1”,而我们的目标是“1 1”,但题目说明了 A1>A2……An,因此不会出现这种情况。

3.第二部分:将剩余的逆串复制多一分接在后面,然后求其后缀数组,接下来的做法与第一步类似。

4. 为什么第二部分需要复制多一份在末尾,而第一部分不用呢?

答:由于题目声明了A1>A2……An,所以直接求其后缀数组,并得到排名最靠前且满足能分成三段的那个后缀,因为不会出现形如“1 1 2 2 3 3”的串,所以这个后缀一定是最优的;然而,去掉第一段之后,剩下的逆串的原串就可能为类似“1 1 2 2 3 3”的串,即逆串为“3 3 2 2 1 1”,如果直接求其后缀数组,那么得到的第二段为“1”,而我们的目标是“1 1”。为了解决这个问题,可以复制多一份接在后面得到“3 3 2 2 1 1 3 3 2 2 1 1”,然后求后缀数组,取位置在0~len-1且排名靠前且满足能分成两段的。

 

代码如下:

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <algorithm>
  5 #include <vector>
  6 #include <cmath>
  7 #include <queue>
  8 #include <stack>
  9 #include <map>
 10 #include <string>
 11 #include <set>
 12 using namespace std;
 13 typedef long long LL;
 14 const int INF = 2e9;
 15 const LL LNF = 9e18;
 16 const int MOD = 1e9+7;
 17 const int MAXN = 4e5+100;
 18 
 19 bool cmp(int *r, int a, int b, int l)
 20 {
 21     return r[a]==r[b] && r[a+l]==r[b+l];
 22 }
 23 
 24 int r[MAXN], sa[MAXN], Rank[MAXN], height[MAXN];
 25 int t1[MAXN], t2[MAXN], c[MAXN];
 26 void DA(int str[], int sa[], int Rank[], int height[], int n, int m)
 27 {
 28     n++;
 29     int i, j, p, *x = t1, *y = t2;
 30     for(i = 0; i<m; i++) c[i] = 0;
 31     for(i = 0; i<n; i++) c[x[i] = str[i]]++;
 32     for(i = 1; i<m; i++) c[i] += c[i-1];
 33     for(i = n-1; i>=0; i--) sa[--c[x[i]]] = i;
 34     for(j = 1; j<=n; j <<= 1)
 35     {
 36         p = 0;
 37         for(i = n-j; i<n; i++) y[p++] = i;
 38         for(i = 0; i<n; i++) if(sa[i]>=j) y[p++] = sa[i]-j;
 39 
 40         for(i = 0; i<m; i++) c[i] = 0;
 41         for(i = 0; i<n; i++) c[x[y[i]]]++;
 42         for(i = 1; i<m; i++) c[i] += c[i-1];
 43         for(i = n-1; i>=0; i--) sa[--c[x[y[i]]]] = y[i];
 44 
 45         swap(x, y);
 46         p = 1; x[sa[0]] = 0;
 47         for(i = 1; i<n; i++)
 48             x[sa[i]] = cmp(y, sa[i-1], sa[i], j)?p-1:p++;
 49 
 50         if(p>=n) break;
 51         m = p;
 52     }
 53 
 54     int k = 0;
 55     n--;
 56     for(i = 0; i<=n; i++) Rank[sa[i]] = i;
 57     for(i = 0; i<n; i++)
 58     {
 59         if(k) k--;
 60         j = sa[Rank[i]-1];
 61         while(str[i+k]==str[j+k]) k++;
 62         height[Rank[i]] = k;
 63     }
 64 }
 65 
 66 int a[MAXN], M[MAXN];
 67 int main()
 68 {
 69     int n;
 70     scanf("%d", &n);
 71     for(int i = 0; i<n; i++)
 72         scanf("%d", &a[i]);
 73     memcpy(M, a, sizeof(M));
 74     sort(M, M+n);
 75     int m = unique(M, M+n)-M;
 76     for(int i = 0; i<n; i++)    //离散化
 77         r[i] = upper_bound(M, M+m, a[i])-M;
 78     reverse(r, r+n);
 79 
 80     int pos1, pos2;
 81     r[n] = m+1;     //在翻转过后的串尾加个最大值,以保证 “1 1 2 2 3 3” 的情况下第一段取的是“2 2”, 而不是“2”
 82     r[n+1] = 0;     //再加上串尾结束符
 83     DA(r, sa, Rank, height, n+1, m+2);
 84     for(int i = 1; i<=n; i++)
 85         if(n-1-sa[i]<=n-3)  //第一段至多只能到n-3的地方,不然就不能分成三段了
 86         {
 87             pos1 = n-1-sa[i];
 88             break;
 89         }
 90 
 91     int len = n-pos1-1;
 92     for(int i = 0; i<len; i++)  //将剩下的串复制多一份接在后面,中间无需分隔符。
 93         r[len+i] = r[i];
 94     len *= 2;
 95     r[len] = 0;
 96     DA(r, sa, Rank, height, len, m+2);
 97     for(int i = 1; i<=len; i++)
 98         if(sa[i]<len/2 && n-sa[i]-1<=n-2) //第二段至多只能到n-2的地方,不然就将剩下的分成两段了
 99         {
100             pos2 = n-sa[i]-1;
101             break;
102         }
103 
104 //    printf("%d %d\n", pos1, pos2);
105     for(int i = pos1; i>=0; i--) printf("%d\n", a[i]);
106     for(int i = pos2; i>pos1; i--) printf("%d\n", a[i]);
107     for(int i = n-1; i>pos2; i--) printf("%d\n", a[i]);
108 }
View Code

 

posted on 2018-02-27 18:51  h_z_cong  阅读(328)  评论(0编辑  收藏  举报

导航