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\)个非空段,并将每一段分别反转,求能得到的字典序最小的序列 ...
随机推荐
- windows8开发-关于wp7应用迁移到win8 metro风格
虽然微软说,wp7应用移植到win8上面是比较简单,只需要修改部分API和设计原则上的细节,同时它也提供了一份比较简洁的参考文档: 而实际上这种移植的工作量还是不小的,尤其当应用引用了较多底层的API ...
- 远程桌面连接centos 7
首先安装tigervnc-server: yum install tigervnc-server 安装好后,设置 vi /etc/sysconfig/vncservers [root@gateway- ...
- hibernate映射排序
@OneToMany(mappedBy="member") @OrderBy(value = "TousuID desc")
- setTimeout()基础/setInterval()基础
JavaScript提供定时执行代码的功能,叫做定时器(timer),主要由setTimeout()和setInterval()这两个函数来完成.它们向任务队列添加定时任务.初始接触它的人都觉得好简单 ...
- Android Activity间动画跳转
本博文主要介绍activity间动画跳转的问题,在这里讲一下怎么设置全部activity的动画跳转和退出跳转.事实上有些软件已经这样做了.比方我们都比較熟悉的大众点评网. 以下我们通过一个实例来看一下 ...
- C语言批量数据到动态二维数组
上一篇文章将文件读取放到静态创建的二维数组中,可是结合网络上感觉到今天的DT时代,这样批量大量读取一个上百行的数据,分配的内存是否可能由于大量的数据而产生溢出呢,近期一直研究里malloc函数.通过它 ...
- NGINX配置文件优化示例
Nginx主配置文件 upstream.conf配置文件 # server nginx配置文件最好分开写,不要把所有的逻辑都放在一个文件里面,会看着很麻烦,,之前我的配置文件都放一起了,,导致现在维护 ...
- 树莓派 CPU & 主板 温度
CPU cat /sys/class/thermal/thermal_zone0/temp | awk '{print $1/1000}' 主板 /opt/vc/bin/vcgencmd measur ...
- 使用Docker开发NodeJs APP
英文版原文地址 这是两篇连载文章的第一篇,讲解了如何使用 Docker 替代 Vagrant 开发基于 Express 框架的NodeJs App的部分细节.不过,这次要增加点难度:我们要使用 con ...
- nyist oj 37 回文字符串 (动态规划经典)
回文字符串 时间限制:3000 ms | 内存限制:65535 KB 难度:4 描写叙述 所谓回文字符串,就是一个字符串.从左到右读和从右到左读是全然一样的.比方"aba".当 ...