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 ...
随机推荐
- Android学习总结(十三) ———— ListView 简单用法
一.ListView的基本概念 在Android所有常用的原生控件当中,用法最复杂的应该就是ListView了,它专门用于处理那种内容元素很多,手机屏幕无法展示出所有内容的情况.ListView可以使 ...
- Maven添加本地依赖
在写本文的时候先来说明一下maven依赖的各种范围的意思 compile(编译范围) compile 是默认的范围:如果没有提供一个范围,那该依赖的范围就是编译范围.编译范围依赖在所有的c ...
- python中的循环语句-01
接触python已经一周时间,下面针对这一周python学习的情况做一梳理: 1)单行注释,使用一个#:多行注释,使用三个单引号(或者三个双引号)如: name = input("name: ...
- python之路——目录
目录 python基础部分 基础部分 介绍.基本语法.流程控制 列表 元祖 字符串 字典 集合 文件操作 函数 变量 递归 迭代器,生成器,装饰器,Json和pickle 数据序列化 函数 初识函数 ...
- 将回车键转换为Tab键
实现效果: 知识运用: KeyEventArgs类的KeyValue属性 public int KeyValue {get;} //获取KeyDown或KeyUp事件的键盘值 SendKeys类的Se ...
- python_111_异常处理
#1 name=['a','s'] try: print(name[3]) except: print('list index out of range')#list index out of ran ...
- Gradle配置最佳实践
https://blog.csdn.net/devilnov/article/details/53321164 本文会不定期更新,推荐watch下项目.如果喜欢请star,如果觉得有纰漏请提交issu ...
- SpringBoot入门,新建SpringBoot项目
一.在Spring Initializr中创建初始化项目 https://start.spring.io/ 二.通过maven导入Idea中(解压后的项目) 解压文件 黄色的为项目需要的真正的代码 , ...
- C语言数据类型_02
C语言数据类型:
- XCode和Cocoa在开发中使用第三方dylib示例
XCode和Cocoa在开发中使用第三方dylib示例 www.educity.cn 发布者:yukowang 来源:网络转载 发布日期:2014年06月13日 XCode和Co ...