【模板】后缀排序(SA数组)
【模板】后缀排序
题目背景
这是一道模板题。
题目描述
读入一个长度为 \(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数组)的更多相关文章
- UOJ.35.[模板]后缀排序(后缀数组 倍增)
题目链接 论找到一个好的教程的正确性.. 后缀数组 下标从1编号: //299ms 2560kb #include <cstdio> #include <cstring> #i ...
- 洛谷.3809.[模板]后缀排序(后缀数组 倍增) & 学习笔记
题目链接 //输出ht见UOJ.35 #include<cstdio> #include<cstring> #include<algorithm> const in ...
- [luogu] P3809 【模板】后缀排序 (SA)
板子,照着题解打的倍增版. #include <iostream> #include <cstdio> #include <cstring> using names ...
- Java后缀数组-求sa数组
后缀数组的一些基本概念请自行百度,简单来说后缀数组就是一个字符串所有后缀大小排序后的一个集合,然后我们根据后缀数组的一些性质就可以实现各种需求. public class MySuffixArrayT ...
- 洛谷:P3809 【模板】后缀排序(后缀数组模板)
P3809 [模板]后缀排序 题目链接:https://www.luogu.org/problemnew/show/P3809 题目背景 这是一道模板题. 题目描述 读入一个长度为 nn 的由大小写英 ...
- [UOJ#35] [UOJ后缀数组模板题] 后缀排序 [后缀数组模板]
后缀数组,解决字符串问题的有利工具,本题代码为倍增SA算法 具体解释详见2009年国家集训队论文 #include <iostream> #include <algorithm> ...
- P3809 【模板】后缀排序
P3809 [模板]后缀排序 从这学的 后缀数组sa[i]就表示排名为i的后缀的起始位置 x[i]是第i个元素的第一关键字 y[i]表示第二关键字排名为i的数,在第一关键字中的位置 #include& ...
- 2018.11.24 loj#111. 后缀排序(后缀数组)
传送门 后缀排序模板题. 终于会后缀数组了(然而只会倍增并不会DC3DC3DC3). 在这里列举几个数组的意思: sai:sa_i:sai:当前排名第iii的后缀的起始下标. rkirk_irki ...
- [洛谷P3809]【模板】后缀排序
[洛谷P3809][模板]后缀排序 题目大意: 对于给定的长度为\(n(n\le10^6)\)的字符串求后缀数组\(sa[i]\). 思路: 倍增+快排构造后缀数组.代码参考<挑战程序设计竞赛& ...
随机推荐
- Apache Ignite - 轉
Ignite Docs Online: ignite-doc-cn https://dongwq.gitbooks.io/ignite-doc/content/index.html - Apache ...
- hiho160周 - 字符串压缩,经典dp
题目链接 小Hi希望压缩一个只包含大写字母'A'-'Z'的字符串.他使用的方法是:如果某个子串 S 连续出现了 X 次,就用'X(S)'来表示.例如AAAAAAAAAABABABCCD可以用10(A) ...
- 快速沃尔什变换(FWT)笔记
开头Orz hy,Orz yrx 部分转载自hy的博客 快速沃尔什变换,可以快速计算两个多项式的位运算卷积(即and,or和xor) 问题模型如下: 给出两个多项式$A(x)$,$B(x)$,求$C( ...
- maven 安装jar包
1 下载maven: 下载路径: http://mirrors.hust.edu.cn/apache/maven/maven-3/3.5.0/binaries/apache-maven-3.5.0-b ...
- mariadb-增删改查怎么用
MariaDB 数据类型 MariaDB数据类型可以分为数字,日期和时间以及字符串值. 使用数据类型的原则:够用就行,尽量使用范围小的,而不用大的 常用的数据类型 整数:int, (bit比整数还要小 ...
- vue-cli 打包 使用 history模式 的后端配置
apache的配置 这是windows下的 在httpd-vhosts.conf文件中把目录指向项目index.html文件所在的位置 # Virtual Hosts # <VirtualHos ...
- Android群英传-拼图游戏puzzle-代码设计和实现
上个周末,3个小时总体上读完了<Android群英传>,本周主要在研究代码层次的设计和实现. 编译安装在手机上,玩了几把,结合代码,一周时间才掌握了整体的思路. 大部分时间,其实花在了 ...
- C语言程序设计:现代方法阅读笔记
第二十六章 atexit函数允许用户“注册”在程序终止时要调用的函数:atexit(func); 在程序终止后,func函数会被自动调用 clock()函数可以计算程序运行时间 time函数返回当前的 ...
- 题解 P3413 【SAC#1 - 萌数】
这道题刚开始正向思维,然后处理重复的时候咕咕了. 参考了@巨型方块 大佬的题解后AC了,在这里就说几个我觉得比较重要或是容易被忽略的点,然后补充一些跳过的证明. 这道题的状态可以设为$dp[i][j] ...
- Opencv 三对角线矩阵(Tridiagonal Matrix)解法之(Thomas Algorithm)
1. 简介 三对角线矩阵(Tridiagonal Matrix),结构如公式(1)所示: aixi−1+bixi+cixx+1=di(1) 其中a1=0,cn=0.写成矩阵形式如(2): ⎡⎣⎢⎢⎢⎢ ...