POJ3581 Sequence —— 后缀数组
题目链接:https://vjudge.net/problem/POJ-3581
| Time Limit: 5000MS | Memory Limit: 65536K | |
| Total Submissions: 7754 | Accepted: 1761 | |
| 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 ≤ 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
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 —— 后缀数组的更多相关文章
- POJ3581:Sequence(后缀数组)
Description Given a sequence, {A1, A2, ..., An} which is guaranteed A1 > A2, ..., An, you are to ...
- POJ 3581 Sequence(后缀数组)
Description Given a sequence, {A1, A2, ..., An} which is guaranteed A1 > A2, ..., An, you are to ...
- POJ 3581 Sequence ——后缀数组 最小表示法
[题目分析] 一见到题目,就有了一个显而易见obviously的想法.只需要每次找到倒过来最小的那一个字符串翻转就可以了. 然而事情并不是这样的,比如说505023这样一个字符串,如果翻转了成为320 ...
- POJ 3581 Sequence [后缀数组]
Sequence Time Limit: 5000MS Memory Limit: 65536K Total Submissions: 6911 Accepted: 1543 Case Tim ...
- POJ3581 Sequence(后缀数组)
题意:给一个串,串的第一个字符比后面的都大,要把它分成三段,然后反转每一段,求能得到的字典序最小的串是什么. 首先,第一段是可以确定的:把原串反转,因为第一个字符是最大的,它是唯一的,不存在反转串的后 ...
- 后缀数组 POJ 3581 Sequence
题目链接 题意:把n个数字(A1比其他数字都大)的序列分成三段,每段分别反转,问字典序最小的序列. 分析:因为A1比其他数字都大,所以反转后第一段结尾是很大的数,相当是天然的分割线,第一段可以单独考虑 ...
- Codeforces VK Cup 2015 A.And Yet Another Bracket Sequence(后缀数组+平衡树+字符串)
这题做得比较复杂..应该有更好的做法 题目大意: 有一个括号序列,可以对其进行两种操作: · 向里面加一个括号,可以在开头,在结尾,在两个括号之间加. · 对当前括号序列进 ...
- POJ 3581 Sequence(后缀数组)题解
题意: 已知某字符串\(str\)满足\(str_1 > max\{str_2,str_3 \cdots str_n\}\),现要求把这个字符串分成连续的三组,然后每组都翻转,问字典序最小是什么 ...
- [POJ3581]Sequence
[POJ3581]Sequence 题目大意: 给定序列\(A_{1\sim n}\),其中\(A_1\)为最大的数.要把这个序列分成\(3\)个非空段,并将每一段分别反转,求能得到的字典序最小的序列 ...
随机推荐
- 【数据售卖平台】—— Vue2.0入门学习项目爬坑
前言:这个项目是我从零学习Vue2.0时用于练习基础知识的入门项目,包含了Vue2.0几乎所有项目都会用到的基础功能,是新手用来练手的好项目,这里温故知新对功能点做一个总结.github地址:http ...
- Win10蓝屏代码
UNEXPECTED_STORE_EXCEPTION “意外存储异常”是Windows 10上的“停止错误”,表示存储组件发生意外异常. 原因 固态硬盘驱动与当前固态硬盘驱动程序不兼容或是当前固态硬盘 ...
- JavaScript中给二维数组动态添加元素的质朴方法
var myData = new Array(); for(var i=0;i<tableDatas.length;i++){ var arr=tableDatas[i]; ...... /// ...
- JavaScript中推断一个对象是否为"空对象”
JavaScript中推断一个对象是否为"空对象" 这里指的"空对象"是类似于:{ } 和 new Object() 这种. 详细的代码实现和原理例如以下: / ...
- React学习之redux
在阅读本文之前,希望大家对以下知识点能提前有所了解并且上好厕所(文章有点长): 状态提升的概念 react高阶组件(函数) es6基础 pure 组件(纯函数) Dumb 组件 React.js的co ...
- NodeJS 安装cnpm命令行工具
在安装之前,请确保已安装Git和NodeJS. cmd机内命令窗口,输入以下命令: git config --system http.sslcainfo /bin/curl-ca-bundle.crt ...
- oracle 表压缩技术
压缩表是我们维护管理中常常会用到的.以下我们看都oracle给我们提供了哪些压缩方式. 文章摘自"Oracle® Database Administrator's Guide11g Rele ...
- git stash 保存当前工作状态
1. git stash 暂存当前工作状态 2. git stash list 查看暂存列表 3. git stash save 'title' 暂存工作状态并添加说明 4. git stash ...
- Android----SharedPreferences(存储数据)
SharedPreferences详解 我们在开发软件的时候,常需要向用户提供软件参数设置功能,例如我们常用的微信,用户可以设置是否允许陌生人添加自己为好友.对于软件配置参数的保存,如果是在windo ...
- 数字证书中keytool命令使用说明
这个命令一般在JDK\jre\lib\security\目录下操作 keytool常用命令 -alias 产生别名 -keystore 指定密钥库的名称(就像数据库一样的证书库,可以 ...