【模板】后缀排序

题目背景

这是一道模板题。

题目描述

读入一个长度为 \(n\) 的由大小写英文字母或数字组成的字符串,请把这个字符串的所有非空后缀按字典序从小到大排序,然后按顺序输出后缀的第一个字符在原串中的位置。位置编号为 \(1\) 到 \(n\) 。

输入输出格式

输入格式:

一行一个长度为 \(n\) 的仅包含大小写英文字母或数字的字符串。

输出格式:

一行,共 \(n\) 个整数,表示答案。

输入输出样例

输入样例#1: 复制

ababa

输出样例#1: 复制

5 3 1 4 2

说明

\(n <= 10^6\)


一点点理解?

怎么说呢?

后缀数组是用来处理字符串后缀的有效手段。

虽然 DC3 的时间复杂度比 倍增 要少了一个log。

但是我们在平常中还是用倍增更多一些。

倍增是用基数排序来维护的。

事先说明。我学的后缀数组资源来源与自为风月马前卒大佬的博客(强烈推荐)。

rak[i]=表示后缀开头位置为 i 的排名,也是第一关键词

num[i]=桶计数

tp[i]=第二关键词,也就是基数排序的后半段

sa[i]=第i个排名的后缀的开头位置



先来看个图





接下来看代码

void Sort()
{
for(int i=0;i<=m;i++)num[i]=0;
for(int i=1;i<=n;i++)num[rak[i]]++;
for(int i=1;i<=m;i++)num[i]+=num[i-1];
for(int i=n;i>=1;i--)sa[num[rak[tp[i]]]--]=tp[i];
}

这时候比较难理解的就是最后一句对吧,别急,看后面的代码。

	cnt=0;
for(int i=1;i<=w;i++)tp[++cnt]=n-w+i;
for(int i=1;i<=n;i++)if(sa[i]>w)tp[++cnt]=sa[i]-w;

这是第一次倍增时的确定tp[]值的代码。

为什么先把后面的tp[]值赋为后面小于w(w为当前排序的长度)呢?

因为后面的长度小于等于w的字符串,再怎么倍增第二关键词都是空集,就相当于只比第一关键词。

第二句话,如果sa[i]的位置能在倍增时作为前面第一关键词的第二关键词,那么便让当前第二关键词的位置等于第一关键词。

因为这里sa[i]已经排序好了,所以其实我们是已经求好了第二关键词的大小的,这样就只要回到第一关键词的大小比较即可。

此时sa[num[rak[tp[i]]--]=tp[i] 事实上就是在排好了第二关键词的情况下,求出来的第一关键词的sa[]值。不过这一次的sa[]值已经是第一关键词和第二关键词的总和的字符串的位置。


代码

	#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1000100;
char s[N];
int sa[N],rak[N],tp[N],num[N];
int n,m=200;
void Sort(){
for(int i=0;i<=m;i++)num[i]=0;
for(int i=1;i<=n;i++)num[rak[i]]++;
for(int i=1;i<=m;i++)num[i]+=num[i-1];
for(int i=n;i>=1;i--)sa[num[rak[tp[i]]]--]=tp[i];
} void SA_sort(){
for(int i=1;i<=n;i++){
rak[i]=s[i]-'0',tp[i]=i;
}
Sort();
int p=0,w=1,cnt;
while(p<n){
cnt=0;
for(int i=1;i<=w;i++)tp[++cnt]=n-w+i;
for(int i=1;i<=n;i++)if(sa[i]>w)tp[++cnt]=sa[i]-w;
Sort();swap(rak,tp);
rak[sa[1]]=p=1;
for(int i=2;i<=n;i++)
if((tp[sa[i]]==tp[sa[i-1]])&&(tp[sa[i]+w]==tp[sa[i-1]+w]))
rak[sa[i]]=p;
else rak[sa[i]]=++p;
w<<=1;m=p;
}
} int main(){
scanf("%s",s+1);
n=strlen(s+1);
SA_sort();
for(int i=1;i<=n;i++)
{
printf("%d ",sa[i]);
}
return 0;
}

【模板】后缀排序(SA数组)的更多相关文章

  1. UOJ.35.[模板]后缀排序(后缀数组 倍增)

    题目链接 论找到一个好的教程的正确性.. 后缀数组 下标从1编号: //299ms 2560kb #include <cstdio> #include <cstring> #i ...

  2. 洛谷.3809.[模板]后缀排序(后缀数组 倍增) & 学习笔记

    题目链接 //输出ht见UOJ.35 #include<cstdio> #include<cstring> #include<algorithm> const in ...

  3. [luogu] P3809 【模板】后缀排序 (SA)

    板子,照着题解打的倍增版. #include <iostream> #include <cstdio> #include <cstring> using names ...

  4. Java后缀数组-求sa数组

    后缀数组的一些基本概念请自行百度,简单来说后缀数组就是一个字符串所有后缀大小排序后的一个集合,然后我们根据后缀数组的一些性质就可以实现各种需求. public class MySuffixArrayT ...

  5. 洛谷:P3809 【模板】后缀排序(后缀数组模板)

    P3809 [模板]后缀排序 题目链接:https://www.luogu.org/problemnew/show/P3809 题目背景 这是一道模板题. 题目描述 读入一个长度为 nn 的由大小写英 ...

  6. [UOJ#35] [UOJ后缀数组模板题] 后缀排序 [后缀数组模板]

    后缀数组,解决字符串问题的有利工具,本题代码为倍增SA算法 具体解释详见2009年国家集训队论文 #include <iostream> #include <algorithm> ...

  7. P3809 【模板】后缀排序

    P3809 [模板]后缀排序 从这学的 后缀数组sa[i]就表示排名为i的后缀的起始位置 x[i]是第i个元素的第一关键字 y[i]表示第二关键字排名为i的数,在第一关键字中的位置 #include& ...

  8. 2018.11.24 loj#111. 后缀排序(后缀数组)

    传送门 后缀排序模板题. 终于会后缀数组了(然而只会倍增并不会DC3DC3DC3). 在这里列举几个数组的意思: sai:sa_i:sai​:当前排名第iii的后缀的起始下标. rkirk_irki​ ...

  9. [洛谷P3809]【模板】后缀排序

    [洛谷P3809][模板]后缀排序 题目大意: 对于给定的长度为\(n(n\le10^6)\)的字符串求后缀数组\(sa[i]\). 思路: 倍增+快排构造后缀数组.代码参考<挑战程序设计竞赛& ...

随机推荐

  1. Windows环境下使用Guard整合Compass和Livereload进行SASS的开发

    配置运行环境 Guard,Compass 和 Livereload 是 Ruby 的 Gem 套件,需要 Ruby 运行环境.另外还需要安装 Ruby 的扩展开发包 Development-Kit,以 ...

  2. SAI / PS绘画一个卡通女孩详解

    本教程介绍使用SAI / PS绘画一个卡通女孩的教程 ,教程很详细,动起你的小手一起来试试吧! 软件下载:http://www.dongmansoft.com/xiazai.html 想要Get到更多 ...

  3. CorelDRAW X6低价再次冲破底线

    平时我们看到的标志设计.杂志排版.产品商标.插图描画......这些都是设计师们使用CorelDRAW设计而来.如今CorelDRAW已经成为每个设计师必装的软件,从12年发布CorelDRAW X6 ...

  4. Ueditor富编辑器

    坑多的Ueditor富编辑器 第一步:修改serverUrl: window.BASEPATH + "notice/word" 第二部:添加依赖包 <dependency&g ...

  5. 洛谷P1231 教辅的组成 网络流

    Code: #include<cstdio> #include<cstring> #include<algorithm> #include<vector> ...

  6. ajax 不执行

    1.get形式访问: 一个相同的URL 只有一个结果,所以 第二次访问的时候 如果 URL字符串没变化 浏览器是 直接拿出了第一次访问的结果,post则不会 解决办法: 1.url+new Date( ...

  7. 关于bom ef+bb+bf的问题

    今天在商品详细页头部出现了一行空白,各种尝试无果,最后怀疑是不是bom头的问题,经过断点跟踪调试逐步缩小范围,果然最后发现是一个语言包文件的开头有 ef bb bf样式的字节,用ultraedit另存 ...

  8. 小A点菜 水题 dp 背包

    基本上还是01背包,首先注意必须正好花光钱,所以初始化时除了dp[0]以外其他都要设置成inf,然后因为求方案数,所以基本方程为dp[i] = dp[i-x] + dp[i],再根据inf进行一些特殊 ...

  9. POJ——T1860 Currency Exchange

    http://poj.org/problem?id=1860 Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 29874   ...

  10. Qt之自定义布局管理器(QCardLayout)

    简述 手动布局另一种方法是通过继承QLayout类编写自己的布局管理器. 下面我们详细来举一个例子-QCardLayout.它由同名的Java布局管理器启发而来.也被称之为卡片布局,每个项目偏移QLa ...