正好写这个博客和我的某个别的需求重合了。。。我就来讲一讲SAM啦qwq

后缀自动机,也就是SAM,是一种极其有用的处理字符串的数据结构,可以用于处理几乎任何有关于子串的问题,但以学起来异常困难著称(在机房里,最先学会SAM的永远是大佬(比如litble和zyf(他在退役前就学了)))。

但是!!!当你学了SAM并熟练地刷了几道题后,你会发现——你之前为了学SAM而强行理解的许多定理,对你应用SAM一点用处也没有!为了引出构造算法,几乎所有博客都会详细地解释“你为啥要这样做”,然鹅。。。

SAM完全可以当成黑盒来用!!!!!!

所以我打算写一篇SAM速成博客。。。保证即学即会!

在构建之前你不得不知道的

Warning:想彻底理解后缀自动机吗?那你有好消息了!请立即关闭此页面,在百度里搜索“后缀自动机 陈立杰”,开始愉快的学习吧!(讲真,陈老师的ppt是讲的最好的,别的博客无能出其右者)

SAM是一个DAG(有向无环图),每个点代表一个"状态",边代表状态转移,边上有一个字母。SAM有一个起始状态(称为起点),从起点开始,沿着边不断走下去,就可以得到一个字符串。记当前停留节点为\(x\),走出来的字符串为\(S\),称节点\(x\)可代表字符串\(S\)。记\(x\)可代表的串中长度最长的串的长度为\(len(x)\)。

另外,除起点外的每个节点还拥有一个“后缀链接“,记作\(fa(x)\)。后缀链接组成了一棵树,别的性质在构建完之后再讲。

存储SAM利用的是类似于Trie树的存储结构,即使用\(ch[][26]\)数组保存状态转移的边。

知道了这些,构建SAM的工作就可以开始了。

开始建造后缀自动机

准备工作:建立数组\(ch,fa,len\),准备指针\(last,cnt\)。SAM的构造方法是不断地向已经建好的SAM中加入新的节点。\(last\)表示上一个被插入的节点,\(cnt\)表示SAM中的节点数量。一开始,\(last=cnt=1\),表示只有一个起点的初始SAM。

接下来,假设要往SAM里加入一个字符\(x\)。

  1. 新建节点\(np=++cnt\)。新建节点\(p\)。\(p=last\)。$ last=np$。
  2. 如果不存在\(ch[p][x]\),令\(ch[p][x]=np,p=fa[p]\)。重复此步骤。
  3. 如果到最后还没有一个\(p\)拥有儿子\(x\),令\(fa[np]=1\)。退出过程。
  4. 当\(ch[p][x]​\)出现时,令\(q=ch[p][x]​\)。如果\(len[q]==len[p]+1​\),令\(fa[np]=q​\)。退出过程。
  5. 否则有点麻烦。新建节点\(nq=++cnt\),将\(q\)的儿子都复制给\(nq\),令\(len[nq]=len[p]+1\)。
  6. 令\(fa[nq]=fa[q],fa[q]=fa[np]=nq\)。
  7. 从\(p\)开始沿着后缀链接,将所有\(ch[p][x]==q\)的节点的\(ch[p][x]\)都替换成\(nq\)。

将你的字符串的所有字符都一一进行如上操作后,你就得到了用你的字符串构建出来的SAM。

你不需要知道为什么这么操作可以得到SAM,你只需要记下以下的代码,做几道题强化记忆,然后就可以用SAM的性质来秒题了。

void insert(int x)
{
int np=++cnt,p=last;
len[np]=len[p]+1,last=np;
while(p&&!ch[p][x])ch[p][x]=np,p=fa[p];
if(!p)fa[np]=1;
else
{
int q=ch[p][x];
if(len[q]==len[p]+1)fa[np]=q;
else
{
int nq=++cnt;len[nq]=len[p]+1;
memmove(ch[nq],ch[q],sizeof(ch[nq]));
fa[nq]=fa[q],fa[np]=fa[q]=nq;
while(ch[p][x]==q)ch[p][x]=nq,p=fa[p];
}
}
}

后缀自动机的奇妙性质

现在,你已经拥有SAM了,你需要知道它有什么用。这里列举了SAM的一些基本且常用的性质。

请牢记以下每一条内容!都十分有用!不要去问“为什么是这样的”!(如果一定要问,请参照上文蓝色放大的Warning)

首先,SAM的点数与边数都是\(O(n)\)的。记住,由于每次插入最多新建两个点,所以应该开字符总量两倍的空间。计算空间时别忘了你开了26倍的\(ch\)数组。

在SAM上从起点开始沿着边随便走走,得到的一定是子串。同时,每一个子串都可以在SAM上走出一条唯一对应的路径。也就是说,子串和SAM上从起点开始的每一条路径一一对应。路径数等于子串数。

起点可以看做是代表空串的点。

重点:定义子串的\(right\)集合:这个子串在原串中所有出现的位置的右端点的集合。

比如说:AAAABBAAAAABAAABBAA

子串AAB出现了3次,右端点集合为\(\{5,12,16\}\)。这就是子串AAB的\(right\)集合。

一个节点能够代表的所有子串的\(right\)集合是一样的。\(right\)集合相等的子串一定被同一个节点代表。(所以,我们会使用“节点的\(right\)集合”这个说法。)两个节点的\(right\)集合之间要么真包含,要么没有交集。若节点\(y\)的\(right\)集合包含了节点\(x\)的\(right\)集合,那么\(y\)能代表的子串均为\(x\)能代表的子串的真后缀。

重点:定义节点\(x\)的后缀链接\(fa(x)\):如果有一些节点的\(right\)集合包含了\(x\)的\(right\)集合,\(fa(x)\)是其中\(right\)集合的大小最小的那一个。

后缀链接们组成了一棵“后缀链接树”(不是后缀树)。后缀链接树的根为起点。若节点\(y\)的\(right\)集合包含了节点\(x\)的\(right\)集合,那么\(y\)在后缀链接树上是\(x\)的祖先。

一个节点的\(right\)集合等于他在后缀链接树上的所有儿子的\(right\)集合的并集。而且儿子的\(right\)集合之间两两没有交集。

每个节点能代表的子串的长度范围是一段连续的区间。这很好理解,因为它们的结束位置都是相同的。

我们求出每个节点能代表的最长串的长度(即\(len(x)\))了,那最短长度呢?其实就等于后缀父亲节点的\(len+1\)。也就是说,所有本质不同的子串的数量等于\(\sum len(x)-len(fa(x))\)。

总结

以上就是SAM的基本性质~对于一道特定的题,你可能需要通过上面的性质推出你需要的新性质。如果你还有什么疑问可以向我留言,我(在退役前)会在一天之内回复的!(你也可以去问更强的boshi和litble,别去问zyf因为他已经退役了。)

题单我就不给了,因为网上有很多很多。。。

当然,如果你立志要当大佬。。。那赶紧打开陈立杰的ppt吧=。=

感谢您的观看qwq!

后缀自动机(SAM)速成手册!的更多相关文章

  1. [转]后缀自动机(SAM)

    原文地址:http://blog.sina.com.cn/s/blog_8fcd775901019mi4.html 感觉自己看这个终于觉得能看懂了!也能感受到后缀自动机究竟是一种怎样进行的数据结构了. ...

  2. 【算法】后缀自动机(SAM) 初探

    [自动机] 有限状态自动机的功能是识别字符串,自动机A能识别字符串S,就记为$A(S)$=true,否则$A(S)$=false. 自动机由$alpha$(字符集),$state$(状态集合),$in ...

  3. SPOJ 1811. Longest Common Substring (LCS,两个字符串的最长公共子串, 后缀自动机SAM)

    1811. Longest Common Substring Problem code: LCS A string is finite sequence of characters over a no ...

  4. 后缀自动机SAM学习笔记

    前言(2019.1.6) 已经是二周目了呢... 之前还是有一些东西没有理解到位 重新写一下吧 后缀自动机的一些基本概念 参考资料和例子 from hihocoder DZYO神仙翻译的神仙论文 简而 ...

  5. 浅谈后缀自动机SAM

    一下是蒟蒻的个人想法,并不很严谨,仅供参考,如有缺误,敬请提出 参考资料: 陈立杰原版课件 litble 某大神 某大神 其实课件讲得最详实了 有限状态自动机 我们要学后缀自动机,我们先来了解一下自动 ...

  6. 后缀自动机(SAM)奶妈式教程

    后缀自动机(SAM) 为了方便,我们做出如下约定: "后缀自动机" (Suffix Automaton) 在后文中简称为 SAM . 记 \(|S|\) 为字符串 \(S\) 的长 ...

  7. 【算法】后缀自动机(SAM) 例题

    算法介绍见:http://www.cnblogs.com/Sakits/p/8232402.html 广义SAM资料:https://www.cnblogs.com/phile/p/4511571.h ...

  8. 【算法专题】后缀自动机SAM

    后缀自动机是用于识别子串的自动机. 学习推荐:陈立杰讲稿,本文记录重点部分和感性理解(论文语言比较严格). 刷题推荐:[后缀自动机初探],题目都来自BZOJ. [Right集合] 后缀自动机真正优于后 ...

  9. 【文文殿下】对后缀自动机(SAM)的理解

    后缀自动机,是一种数据结构,是由状态和转移关系构成的.它虽然叫做后缀自动机,可是他却与后缀并没有什么太大的联系. 后缀自动机的每一种状态都是原串的一些子串的集合,每个子串只唯一存在于某个状态中,对每一 ...

随机推荐

  1. FFT自看

    https://www.cnblogs.com/RabbitHu/p/FFT.html  先去看这个... 我觉得代码还是https://blog.csdn.net/WADuan2/article/d ...

  2. 自学Zabbix3.5.3-监控项item-zabbix agent 类型所有key

    点击返回:自学Zabbix之路 点击返回:自学Zabbix4.0之路 点击返回:自学zabbix集锦 1. 温习       Zabbix server是Zabbix软件的中心进程. Server执行 ...

  3. 【Revit API】梁的净高分析

    原理就是,先从梁的LocationCurve上取点,然后向板的上表面投影.如果有投影点,再从投影点(板上)向梁的底面投影,这时候如果有投影点的话就能得到距离了. 运用该分析的第一条件是梁是在板的上方, ...

  4. 【BZOJ3832】[POI2014]Rally(拓扑排序,动态规划)

    [BZOJ3832][POI2014]Rally(拓扑排序,动态规划) 题面 BZOJ,权限题 洛谷 题解 这题好强啊,感觉学了好多东西似的. 首先发现了一个图画的很好的博客,戳这里 然后我来补充一下 ...

  5. 【BZOJ1082】[SCOI2005]栅栏(搜索)

    [BZOJ1082][SCOI2005]栅栏(搜索) 题面 BZOJ 洛谷 题解 随便写个爆搜,洛谷上就\(80\)分了.先放爆搜代码: #include<iostream> #inclu ...

  6. linux driver error ------ 编译驱动出现 ERROR: Kernel configuration is invalid

       ERROR: Kernel configuration is invalid.         include/generated/autoconf.h or include/config/au ...

  7. linux开启swap(磁盘缓存)操作

    转载 2014年04月26日 14:41:15 4470 由于工作需要,要帮助同事查看linux服务器的缓存开启情况,经过查找资料,可确定通过以下方法确定Linux磁盘缓存是否已开启. 1.命令行下执 ...

  8. [Apio2012]dispatching 左偏树做法

    http://codevs.cn/problem/1763/ 维护子树大根堆,当子树薪水和>m时,删除最贵的点 #include<cstdio> #include<iostre ...

  9. 一个Zabbix agent配置多个Zabbix Server

    环境说明: 公司和政府合作的项目中,需要对服务器添加监控.政府方面已对服务部署了zabbix agent,实现了系统层面的基础监控:而对于公司而言,需要对服务器上的服务进行监控,故需在原有的zabbi ...

  10. Java Web之路(二)Servlet之HttpServletResponse和HttpServletRequest

    HttpServletResponse 1.告诉服务器应用使用UTF-8解析文本的两种方式,告诉客户端要使用什么编码 response.setHeader("content-type&quo ...