题目链接: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且排名靠前且满足能分成两段的。

代码如下:

 #include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <string>
#include <set>
using namespace std;
typedef long long LL;
const int INF = 2e9;
const LL LNF = 9e18;
const int MOD = 1e9+;
const int MAXN = 4e5+; bool cmp(int *r, int a, int b, int l)
{
return r[a]==r[b] && r[a+l]==r[b+l];
} int r[MAXN], sa[MAXN], Rank[MAXN], height[MAXN];
int t1[MAXN], t2[MAXN], c[MAXN];
void DA(int str[], int sa[], int Rank[], int height[], int n, int m)
{
n++;
int i, j, p, *x = t1, *y = t2;
for(i = ; i<m; i++) c[i] = ;
for(i = ; i<n; i++) c[x[i] = str[i]]++;
for(i = ; i<m; i++) c[i] += c[i-];
for(i = n-; i>=; i--) sa[--c[x[i]]] = i;
for(j = ; j<=n; j <<= )
{
p = ;
for(i = n-j; i<n; i++) y[p++] = i;
for(i = ; i<n; i++) if(sa[i]>=j) y[p++] = sa[i]-j; for(i = ; i<m; i++) c[i] = ;
for(i = ; i<n; i++) c[x[y[i]]]++;
for(i = ; i<m; i++) c[i] += c[i-];
for(i = n-; i>=; i--) sa[--c[x[y[i]]]] = y[i]; swap(x, y);
p = ; x[sa[]] = ;
for(i = ; i<n; i++)
x[sa[i]] = cmp(y, sa[i-], sa[i], j)?p-:p++; if(p>=n) break;
m = p;
} int k = ;
n--;
for(i = ; i<=n; i++) Rank[sa[i]] = i;
for(i = ; i<n; i++)
{
if(k) k--;
j = sa[Rank[i]-];
while(str[i+k]==str[j+k]) k++;
height[Rank[i]] = k;
}
} int a[MAXN], M[MAXN];
int main()
{
int n;
scanf("%d", &n);
for(int i = ; i<n; i++)
scanf("%d", &a[i]);
memcpy(M, a, sizeof(M));
sort(M, M+n);
int m = unique(M, M+n)-M;
for(int i = ; i<n; i++) //离散化
r[i] = upper_bound(M, M+m, a[i])-M;
reverse(r, r+n); int pos1, pos2;
r[n] = m+; //在翻转过后的串尾加个最大值,以保证 “1 1 2 2 3 3” 的情况下第一段取的是“2 2”, 而不是“2”
r[n+] = ; //再加上串尾结束符
DA(r, sa, Rank, height, n+, m+);
for(int i = ; i<=n; i++)
if(n--sa[i]<=n-) //第一段至多只能到n-3的地方,不然就不能分成三段了
{
pos1 = n--sa[i];
break;
} int len = n-pos1-;
for(int i = ; i<len; i++) //将剩下的串复制多一份接在后面,中间无需分隔符。
r[len+i] = r[i];
len *= ;
r[len] = ;
DA(r, sa, Rank, height, len, m+);
for(int i = ; i<=len; i++)
if(sa[i]<len/ && n-sa[i]-<=n-) //第二段至多只能到n-2的地方,不然就将剩下的分成两段了
{
pos2 = n-sa[i]-;
break;
} // printf("%d %d\n", pos1, pos2);
for(int i = pos1; i>=; i--) printf("%d\n", a[i]);
for(int i = pos2; i>pos1; i--) printf("%d\n", a[i]);
for(int i = n-; i>pos2; i--) printf("%d\n", a[i]);
}

POJ3581 Sequence —— 后缀数组的更多相关文章

  1. POJ3581:Sequence(后缀数组)

    Description Given a sequence, {A1, A2, ..., An} which is guaranteed A1 > A2, ..., An,  you are to ...

  2. POJ 3581 Sequence(后缀数组)

    Description Given a sequence, {A1, A2, ..., An} which is guaranteed A1 > A2, ..., An,  you are to ...

  3. POJ 3581 Sequence ——后缀数组 最小表示法

    [题目分析] 一见到题目,就有了一个显而易见obviously的想法.只需要每次找到倒过来最小的那一个字符串翻转就可以了. 然而事情并不是这样的,比如说505023这样一个字符串,如果翻转了成为320 ...

  4. POJ 3581 Sequence [后缀数组]

    Sequence Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 6911   Accepted: 1543 Case Tim ...

  5. POJ3581 Sequence(后缀数组)

    题意:给一个串,串的第一个字符比后面的都大,要把它分成三段,然后反转每一段,求能得到的字典序最小的串是什么. 首先,第一段是可以确定的:把原串反转,因为第一个字符是最大的,它是唯一的,不存在反转串的后 ...

  6. 后缀数组 POJ 3581 Sequence

    题目链接 题意:把n个数字(A1比其他数字都大)的序列分成三段,每段分别反转,问字典序最小的序列. 分析:因为A1比其他数字都大,所以反转后第一段结尾是很大的数,相当是天然的分割线,第一段可以单独考虑 ...

  7. Codeforces VK Cup 2015 A.And Yet Another Bracket Sequence(后缀数组+平衡树+字符串)

    这题做得比较复杂..应该有更好的做法 题目大意: 有一个括号序列,可以对其进行两种操作: ·        向里面加一个括号,可以在开头,在结尾,在两个括号之间加. ·        对当前括号序列进 ...

  8. POJ 3581 Sequence(后缀数组)题解

    题意: 已知某字符串\(str\)满足\(str_1 > max\{str_2,str_3 \cdots str_n\}\),现要求把这个字符串分成连续的三组,然后每组都翻转,问字典序最小是什么 ...

  9. [POJ3581]Sequence

    [POJ3581]Sequence 题目大意: 给定序列\(A_{1\sim n}\),其中\(A_1\)为最大的数.要把这个序列分成\(3\)个非空段,并将每一段分别反转,求能得到的字典序最小的序列 ...

随机推荐

  1. 常用jar包之commons-digester使用

    常用jar包之commons-digester使用 学习了:https://blog.csdn.net/terryzero/article/details/4332257 注意了, digester. ...

  2. hibernate 数据缓存

    http://www.cnblogs.com/wean/archive/2012/05/16/2502724.html,

  3. winform制作自定义控件

    一 .概述Windows 窗体控件是可再次使用的组件,它们封装了用户界面功能,并且可以用于客户端 Windows 应用程序.“Windows 窗体”不仅提供了许多现成控件,还提供了自行开发控件的基础结 ...

  4. SharePoint 的PowerShell命令之获取所有网站模版

    Get-SPWebTemplate | select Name, Title

  5. VueJS计算属性: computed

    computed属性 HTML <!DOCTYPE html> <html> <head> <meta charset="utf-8"&g ...

  6. 基于Repository模式设计项目架构—你可以参考的项目架构设计

    关于Repository模式,直接百度查就可以了,其来源是<企业应用架构模式>.我们新建一个Infrastructure文件夹,这里就是基础设施部分,EF Core的上下文类以及Repos ...

  7. Python 规范化LinkedIn用户联系人的职位名

    CODE: #!/usr/bin/python # -*- coding: utf-8 -*- ''' Created on 2014-8-19 @author: guaguastd @name: j ...

  8. 如何在DOS窗口中显示UTF-8字符

    在中文Windows系统中,如果一个文本文件是UTF-8编码的,那么在CMD.exe命令行窗口(所谓的DOS窗口)中不能正确显示文件中的内容.在默认情况下,命令行窗口中使用的代码页是中文或者美国的,即 ...

  9. android开发系列之ContentObserver

    在这篇博客里面我想要分享一下自己最近在项目里面遇到一个比较好的数据同步解决方案,首先让我们先来看看该方案的应用场景:我们在客户端本地利用数据库缓存了一些数据,当我们检测到数据库里面的数据发生变化的时候 ...

  10. Synchronized修饰静态变量和普通变量的区别

    这里主要涉及到类对象(static方法),对象方法(非static方法) 我们知道,当synchronized修饰一个static方法时,多线程下,获取的是类锁(即Class本身,注意:不是实例): ...