【模板】后缀排序(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]\). 思路: 倍增+快排构造后缀数组.代码参考<挑战程序设计竞赛& ...
随机推荐
- 【英雄会】微软题目:几个bing
今天是元旦,开篇先祝福大家在新的一年心想事成,工作顺利,开心生活每一天 . 看到[英雄会]上出现了微软出的题目:几个bing,题目内容如下: 本届大赛由微软必应词典冠名,必应词典(Bing Dicti ...
- jquery 几种类选择器方式
代码如下: <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="TestClas ...
- 用Maven创建第一个web项目Struts2项目
一.创建一个web项目 参考前面文章,项目名:maven-struts-demo. 二.配置pom.xml文件添加struts2依赖 <project xmlns="http://ma ...
- SpringCloud学习笔记(13)----Spring Cloud Netflix之Hystrix断路器的隔离策略
说明 : 1.Hystrix通过舱壁模式来隔离限制依赖的并发量和阻塞扩散 2. Hystrix提供了两种隔离策略:线程池(THREAD)和信号量隔离SEMAPHORE). 1. 线程池隔离(默认策略模 ...
- 路飞学城Python-Day17
[1.编程范式] 1.面向过程编程 2.面向对象编程 [2.面向过程编程] 面向过程:核心就是过程 什么是过程? 过程指的是解决问题的步骤,先做什么,在作什么,面向过程就像是设计一个流水线,是一种 ...
- BZOJ 2287 【POJ Challenge】消失之物(DP+容斥)
2287: [POJ Challenge]消失之物 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 986 Solved: 572[Submit][S ...
- BZOJ 2565 最长双回文串(manacher)
565: 最长双回文串 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 3343 Solved: 1692[Submit][Status][Discu ...
- redis搭建与安装
redis提供五种数据类型:string,hash,list,set及zset(sorted set). 第一部分:安装redis 希望将redis安装到此目录 1 /usr/local/redis ...
- Ubuntu 16.04 Chrome浏览器安装flash player插件
1:官网下载插件 flash palyer lash_player_npapi_linux_debug.x86_64.tar.gz 2:解压 提取 libpepflashplayer.so 3:手动 ...
- Zabbix分布式配置
Zabbix是一个分布式监控系统,它可以以一个中心点.多个分节点的模式运行,使用Proxy能大大的降低Zabbix Server的压力,Zabbix Proxy可以运行在独立的服务器上,安装Zabbi ...