SA 后缀数组

首先一定要确定\(SA\)是个什么东西

\(SA[i]\)表示的是排名为\(i\)的后缀是哪一个

至于后缀\(i\)的排名是多少,那个是\(rank[i]\)


当然啦

最最最难懂的就是基数排序

要是不用基数排序,每次对于一个二元组直接\(sort\)一下

这样的复杂度是\(O(nlog^2)\)

对于二元组的基数排序应该是这样做的:

首先把所有元素按照最后一维丢到依次对应的桶里面

然后顺次取出

再按照第一维依次丢入

再顺次取出

这样就可以排序啦


先把代码丢出来

bool cmp(int i,int j,int k){return y[i]==y[j]&&y[i+k]==y[j+k];}
void GetSA()
{
int m=30;
for(int i=1;i<=n;++i)t[x[i]=a[i]]++;
for(int i=1;i<=m;++i)t[i]+=t[i-1];
for(int i=n;i>=1;--i)SA[t[x[i]]--]=i;
for(int k=1;k<=n;k<<=1)
{
int p=0;
for(int i=0;i<=m;++i)y[i]=0;
for(int i=n-k+1;i<=n;++i)y[++p]=i;
for(int i=1;i<=n;++i)if(SA[i]>k)y[++p]=SA[i]-k;
for(int i=0;i<=m;++i)t[i]=0;
for(int i=1;i<=n;++i)t[x[y[i]]]++;
for(int i=1;i<=m;++i)t[i]+=t[i-1];
for(int i=n;i>=1;--i)SA[t[x[y[i]]]--]=y[i];
swap(x,y);
x[SA[1]]=p=1;
for(int i=2;i<=n;++i)x[SA[i]]=cmp(SA[i],SA[i-1],k)?p:++p;
if(p>=n)break;
m=p;
}
}

首先,第一次做\(k=0\)时

相当于每个后缀的第二维都是一样的

所以,直接按照第一维(也就是自己的值)

进行一次基数排序

接下来

每次基数排序都要利用到上一次的值

还记得吧,基数排序是先按照第二维从小往大拍

那么,我们就先把第二维的顺序搞出来

首先最小的一定就是没有第二维的东西

所以我们先把这些数直接丢进数组里面

接下来就是有第二维的东西啦

第\(i\)位的第二维是啥?\(rank[i+k]\)

所以,从小到达枚举\(SA\),这样保证第二维从小往大

那么,只要\(SA[i]>k\)

就证明它是一个东西的第二维

所以,把\(SA[i]-k\)丢到数组里面去就好啦

这样的话,按照第二维就拍好啦

再来依次按照第一维丢到桶里面去

做一遍基数排序就好啦

这样就能够求出\(SA\)啦

看起来很简单诶。。

只是数组不要搞混了

一定搞清楚每个数组是干啥的

比如我的代码

\(SA\)是后缀数组,\(SA[i]\)表示排名为\(i\)的串是哪一个

\(rank\)相当于排名,\(rank[i]\)表示第\(i\)个串的排名

\(x,y\)两个数组是记录顺序的

分别记录第一维和第二维的排序的顺序

\(t\)是桶

这样我们就很愉快的求出了\(SA\)

还有一个数组\(Height\)

\(Height[i]\)表示串\(SA[i]\)与\(SA[i-1]\)的最长公共前缀的长度

比如说,现在要求后缀\(i\)与\(j\)的最长公共前缀

那就只需要求\(min(Height[i]),i \in [rank[i]+1,rank[j]]\)

因为已经按照字典序排好序啦

\(Height\)显然可以暴力求

但是太不优美

我们有\(Height[rank[i]]>=Height[rank[i-1]]-1\)

证明(来自\(hihoCoder\))

设\(suffix(k)\)是排在\(suffix(i-1)\)前一名的后缀,

则它们的最长公共前缀是\(height[rank[i-1]]\)

那么\(suffix(k+1)\)将排在\(suffix(i)\)的前面(这里要求\(height[rank[i-1]]>1\),如果\(height[rank[i-1]]≤1\),原式显然成立)

并且\(suffix(k+1)\)和\(suffix(i)\)的最长公共前缀是\(height[rank[i-1]]-1\),

所以\(suffix(i)\)和在它前一名的后缀的最长公共前缀至少是\(height[rank[i-1]]-1\)

那么,我们按照\(rank\)的顺序来求\(Height\)就行啦

	for(int i=1;i<=n;++i)Rank[SA[i]]=i;
for(int i=1,j=0;i<=n;++i)
{
if(j)j--;
while(a[i+j]==a[SA[Rank[i]-1]+j])++j;
height[Rank[i]]=j;
}

我现在也不是很熟

以后多做点题我再接着补

SA 后缀数组的更多相关文章

  1. Maximum repetition substring(POJ - 3693)(sa(后缀数组)+st表)

    The repetition number of a string is defined as the maximum number \(R\) such that the string can be ...

  2. Distinct Substrings(spoj694)(sam(后缀自动机)||sa(后缀数组))

    Given a string, we need to find the total number of its distinct substrings. Input \(T-\) number of ...

  3. 【后缀数组之SA数组】【真难懂啊】

    基本上一搜后缀数组网上的模板都是<后缀数组——处理字符串的有力工具>这一篇的注释,O(nlogn)的复杂度确实很强大,但对于初次接触(比如窝)的人来说理解起来也着实有些困难(比如窝就活活好 ...

  4. 关于后缀数组的倍增算法和height数组

    自己看着大牛的论文学了一下后缀数组,看了好久好久,想了好久好久才懂了一点点皮毛TAT 然后就去刷传说中的后缀数组神题,poj3693是进化版的,需要那个相同情况下字典序最小,搞这个搞了超久的说. 先简 ...

  5. Long Long Message(后缀数组)

    Long Long Message Time Limit: 4000MS   Memory Limit: 131072K Total Submissions: 30427   Accepted: 12 ...

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

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

  7. bzoj3796(后缀数组)(SA四连)

    bzoj3796Mushroom追妹纸 题目描述 Mushroom最近看上了一个漂亮妹纸.他选择一种非常经典的手段来表达自己的心意——写情书.考虑到自己的表达能力,Mushroom决定不手写情书.他从 ...

  8. [笔记]后缀数组SA

    参考资料这次是真抄的: 1.后缀数组详解 2.后缀数组-学习笔记 3.后缀数组--处理字符串的有力工具 定义 \(SA\)排名为\(i\)的后缀的位置 \(rk\)位置为\(i\)的后缀的排名 \(t ...

  9. 后缀数组(SA)总结

    后缀数组(SA)总结 这个东西鸽了好久了,今天补一下 概念 后缀数组\(SA\)是什么东西? 它是记录一个字符串每个后缀的字典序的数组 \(sa[i]\):表示排名为\(i\)的后缀是哪一个. \(r ...

随机推荐

  1. SaltStack 与 Python 程序的结合

    SaltStack 库中的 Modules: 在 SaltStack 中,每个子系统插件(plug-in)都是一个 Python Module.因此,SaltStack 库中的 Module 可以看作 ...

  2. 树莓派3B上部署运行.net core 2程序

    针对Linxu arm处理器如何部署.net core 2的资料很少,网上找到几篇但都写得不够详细,按照他们教程来撞墙了,折磨了几天终于部署成功了,先上一张运行成功的图 1.windows系统中,在项 ...

  3. Java多线程应用总结

    一.基本方法 进程和线程一样,都是实现并发的一个基本单位.线程是比进程更小的执行单位,线程是在进程的基础上进行的进一步划分.所谓多线程,是指一个进程在执行过程中可以产生多个更小的程序单元,这些更小的单 ...

  4. vagrant系列教程(一):vagrant的安装与初识(转)

    [参考]https://github.com/astaxie/go-best-practice/blob/master/ebook/zh/01.1.md 阅读目录 下载一个合适的box 完成一个box ...

  5. 在 CentOS7.0 上搭建 Chroot 的 Bind DNS 服务器

    BIND(Berkeley internet Name Daemon)也叫做NAMED,是现今互联网上使用最为广泛的DNS 服务器程序.这篇文章将要讲述如何在 chroot 监牢中运行 BIND,这样 ...

  6. WEB页面的生命周期,DOMContentLoaded,load,beforeunload,unload

    简言 理解WEB页面的生命周期,文档加载事件及顺序对WEB开发有十分的重要意义.如果不理解,在元素未加载就提前操作元素,则得不到想要的结果.而如果页面完全加载完成后,再进行操作,则又会影响用户体验. ...

  7. Hibernate 一对一中的一些问题

    1.对于想查询一对一种一方为空的时候使用 例如一个用户对应一个人,则要从人查找没有用户的人员的话, 使用hql语句是查询不到的 我今天也碰到了这个问题,研究了下,可以用以下语句查出来:from Per ...

  8. 前端JS面试题汇总 Part 2 (null与undefined/闭包/foreach与map/匿名函数/代码组织)

    原文:https://github.com/yangshun/front-end-interview-handbook/blob/master/questions/javascript-questio ...

  9. PHP二维数组排序(感谢滔哥)

    滔哥原创 /* _ooOoo_ o8888888o 88" . "88 (| -_- |) O\ = /O ____/`---'\____ .' \\| |// `. / \\|| ...

  10. mysql 学习心得1

    1由于不靠这玩意吃饭 估计不准备精读 顺便中文版也不用担心翻译问题 科科 大致翻了下=,= mysql的感觉怎么就是背命令.... 2DDL语句 定义数据 创建删除修改 create drop alt ...