POJ 3581 Sequence ——后缀数组 最小表示法
【题目分析】
一见到题目,就有了一个显而易见obviously的想法。只需要每次找到倒过来最小的那一个字符串翻转就可以了。
然而事情并不是这样的,比如说505023这样一个字符串,如果翻转了成为320505.
最小的后缀是05,那么得到的字符串是055023,然而最小的结果是全部翻转,为050523.
因为我们没有考虑到翻转后的字符和未翻转的字符有可能会连接起来,我们并没有考虑到连接部分对答案的影响。
这里我们用最小表示的方法来做这道题目,每次操作完成之后,都需要把翻转后的串复制两遍,这样的话,我们找到在复制的第一遍中的最小的后缀输出。
这样子我们就可以考虑到他本身的翻转和不翻转的部分组成的字符串的大小。
上面的方法就是后缀数组,复制两次的方法其实就是为了求最小表示的开头,为O(nlogn)。
所以我们可以直接用最小表示法来做,而且不需要复制,最小表示法是O(n)的,直接扫一遍就可以得到最小表示的起始位置,然后输出即可。
这样就有了两种方法。
然而人比较懒,练练后缀数组好了。
注意边界的条件(第一次翻转最少剩下两个字符,为后面两次翻转留下空间)。
【代码】
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib> #include <map>
#include <set>
#include <queue>
#include <string>
#include <iostream>
#include <algorithm> using namespace std; #define maxn 800005
#define inf 0x3f3f3f3f
#define F(i,j,k) for (int i=j;i<=k;++i)
#define D(i,j,k) for (int i=j;i>=k;--i) void Finout()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
#endif
} int Getint()
{
int x=0,f=1; char ch=getchar();
while (ch<'0'||ch>'9') {if (ch=='-') f=-1; ch=getchar();}
while (ch>='0'&&ch<='9') {x=x*10+ch-'0'; ch=getchar();}
return x*f;
} int n,a[maxn],b[maxn],top; struct SuffixArray{
int s[maxn];
int tmp[maxn],cnt[maxn],sa[maxn],rk[maxn],h[maxn];
void build(int n,int m)
{
int i,j,k;n++;
F(i,0,2*n+5) tmp[i]=sa[i]=rk[i]=h[i]=0;
F(i,0,m-1) cnt[i]=0;
F(i,0,n-1) cnt[rk[i]=s[i]]++;
F(i,1,m-1) cnt[i]+=cnt[i-1];
F(i,0,n-1) sa[--cnt[rk[i]]]=i;
// cout<<" ";F(i,0,n) cout<<b[s[i]]<<" ";cout<<endl;
for (k=1;k<=n;k<<=1)
{
F(i,0,n-1)
{
j=sa[i]-k;
if (j<0) j+=n;
tmp[cnt[rk[j]]++]=j;
}
sa[tmp[cnt[0]=0]]=j=0;
F(i,1,n-1)
{
if (rk[tmp[i]]!=rk[tmp[i-1]]||rk[tmp[i]+k]!=rk[tmp[i-1]+k]) cnt[++j]=i;
sa[tmp[i]]=j;
}
memcpy(rk,sa,n*sizeof(int));
memcpy(sa,tmp,n*sizeof(int));
if (j>=n-1) break;
}
// cout<<"SA ";F(i,0,n) cout<<sa[i]<<" ";cout<<endl;
// for (j=rk[h[i=k=0]=0];i<n-1;++i,++k)
// while (~k&&s[i]!=s[sa[j-1]+k]) h[j]=k--,j=rk[sa[j]+1];
// cout<<"height ";F(i,0,n) cout<<h[i]<<" "; cout<<endl;
}
}arr; int main()
{
Finout();
n=Getint();
F(i,0,n-1) a[i]=Getint(),b[i]=a[i];
b[n]=-inf;
sort(b,b+n+1);
top=unique(b,b+n+1)-b;
F(i,0,n-1) a[i]=lower_bound(b,b+top,a[i])-b;
F(i,0,n-1) arr.s[n-1-i]=a[i];
arr.s[n]=0;
arr.build(n-1,2005);
// cout<<"build over"<<endl;
int tmp=0;
while (arr.sa[tmp]<2||arr.sa[tmp]>=n) tmp++;
F(i,arr.sa[tmp],n-1) cout<<b[arr.s[i]]<<endl;// cout<<endl;
n-=n-arr.sa[tmp];
F(i,0,n-1) arr.s[i+n]=arr.s[i];
arr.s[2*n]=0;
arr.build(2*n-1,2005);
tmp=0; while (arr.sa[tmp]<1||arr.sa[tmp]>=n) tmp++;
F(i,arr.sa[tmp],n-1) cout<<b[arr.s[i]]<<endl; //cout<<endl;
F(i,0,arr.sa[tmp]-1) cout<<b[arr.s[i]]<<endl; //cout<<endl;
}
POJ 3581 Sequence ——后缀数组 最小表示法的更多相关文章
- POJ 3581 Sequence(后缀数组)
Description Given a sequence, {A1, A2, ..., An} which is guaranteed A1 > A2, ..., An, you are to ...
- POJ 3581 Sequence [后缀数组]
Sequence Time Limit: 5000MS Memory Limit: 65536K Total Submissions: 6911 Accepted: 1543 Case Tim ...
- [POJ 3581]Sequence
[POJ 3581]Sequence 标签: 后缀数组 题目链接 题意 给你一串序列\(A_i\),保证对于$ \forall i \in [2,n],都有A_1 >A_i$. 现在需要把这个序 ...
- 后缀数组 POJ 3581 Sequence
题目链接 题意:把n个数字(A1比其他数字都大)的序列分成三段,每段分别反转,问字典序最小的序列. 分析:因为A1比其他数字都大,所以反转后第一段结尾是很大的数,相当是天然的分割线,第一段可以单独考虑 ...
- POJ 3581 Sequence(后缀数组)题解
题意: 已知某字符串\(str\)满足\(str_1 > max\{str_2,str_3 \cdots str_n\}\),现要求把这个字符串分成连续的三组,然后每组都翻转,问字典序最小是什么 ...
- POJ3581 Sequence —— 后缀数组
题目链接:https://vjudge.net/problem/POJ-3581 Sequence Time Limit: 5000MS Memory Limit: 65536K Total Su ...
- POJ 2406 KMP/后缀数组
题目链接:http://poj.org/problem?id=2406 题意:给定一个字符串,求由一个子串循环n次后可得到原串,输出n[即输出字符串的最大循环次数] 思路一:KMP求最小循环机,然后就 ...
- POJ 1743-POJ - 3261~后缀数组关于最长字串问题
POJ 1743 题意: 有N(1 <= N <=20000)个音符的序列来表示一首乐曲,每个音符都是1~~88范围内的整数,现在要找一个重复的主题.“主题”是整个音符序列的一个子串,它需 ...
- POJ2406 Power Strings —— KMP or 后缀数组 最小循环节
题目链接:https://vjudge.net/problem/POJ-2406 Power Strings Time Limit: 3000MS Memory Limit: 65536K Tot ...
随机推荐
- 【extjs6学习笔记】0.0 准备
1.下载ExtJS 6 下面是Ext JS 6正式版的GPL版本下载地址 https://www.sencha.com/legal/gpl/ 2.下载sencha cmd 安装完成后,命令行运行出现以 ...
- Linux下各文件夹的结构说明及用途介绍(转载)
linux下各文件夹的结构说明及用途介绍: /bin:二进制可执行命令. /dev:设备特殊文件. /etc:系统管理和配置文件. /etc/rc.d:启动的配 置文件和脚本. /home:用户主目录 ...
- git的基本使用命令操作
Linux操作命令行: mkdir - 创建文件夹, cd - 切换文件路径 pwd - 显示文件路径 ls -ah - 可以查看隐藏的文件夹名(.git) cat 文件 ...
- ubuntu 14.04 安装mysql,并配置远程连接和中文乱码
1. 安装MySQL的jar root@computer-PowerEdge-T30:~# sudo apt-get install mysql-server mysql-client在本次安装中,根 ...
- java并发编程:Executor、Executors、ExecutorService
1.Executor和ExecutorService Executor:一个接口,其定义了一个接收Runnable对象的方法executor,其方法签名为executor(Runnable comma ...
- (五)使用Docker镜像(上)
1. 获取镜像 # 获取镜像 docker pull image:tag // 不使用tag 默认下载latest标签的镜像,即最新的镜像. 2. 查看镜像信息 # 查看镜像信息docker imag ...
- haproxy文件的增删改查
在构建一个程序项目之前,首先需要设计程序的框架,从总体上构建一个项目中的一个个功能,之后对每一个功能进行补充,最终实现总体的功能. 1 程序的总体框架: 首先把所有的功能设计成相应的函数,用pass来 ...
- Encryption-基础:MD5加密
环境:vc2003 .h /* MD5.H - header file for MD5C.C */ /* Copyright (C) 1991-2, RSA Data Security, Inc. C ...
- 一、新手必会Python基础
博客内容: 1.基础语法 2.运算符 3.流程控制 4.列表.元组.字典.集合 5.字符串 6.文件操作 一.基础语法 1.标识符 命名规则: 以字母.下划线开头 其他部分由字母.数字或下划线组成 不 ...
- QT5:第八章 信号与槽机制
一.简介 QT编程中信号与槽用于处理界面各个组件的交互,类似与MFC的消息循环和绑定 注意:在使用信号与槽的类中,必须在类的定义中加入宏定义Q_OBJECT 信号(Signal)就是在特定情况下被发射 ...