思路来源

https://www.luogu.com.cn/blog/Kesdiael3/hou-zhui-zi-dong-ji-yang-xie 首推这一篇

https://www.cnblogs.com/zjp-shadow/p/9218214.html 也看了这一篇,也不错

http://hihocoder.com/problemset/problem/1441 hihocoder板子题

https://www.luogu.com.cn/problem/solution/P3804 洛谷板子题

前置知识

自动机的知识(编译原理那一套,比如有限状态自动机云云,知道能在其上沿边转移感觉就可)

AC自动机、Trie树、后缀数组

死记硬背环节

证明和心得(后附)感觉用处不大,直接计入死记硬背和抄板子做题环节

后缀自动机(SAM),是一个最小的确定有限状态自动机(DFA),接受且只接受S的后缀

parent树和自动机节点共用,时间复杂度O(n),空间复杂度O(n)

parent(也称fa,后缀链接link):当一个节点的串,在变为其后缀,且endpos发生了扩大时,最长的那个后缀对应的节点

endpos(也称right):每个节点对应的串的endpos集合是一致的,每个子串唯一出现在某个节点里

len:一个节点内代表的串的最大长度

minlen:一个节点内代表的串的最小长度,由于a回跳到父亲fa(a)的时候len(fa)+1=minlen(a),故一般不存

ch[0-26](后缀转移transfer):自动机上对应字母的转移

配合两张图食用,便于记忆这些概念

图1:abcd的后缀自动机,

红色括号是endpos集合,字母是自动机转移

图二:aaba的后缀自动机,

红色数字是节点对应的最长子串的长度len,蓝边是其parent树上的父亲fa

板子

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
struct NODE
{int ch[26];int len,fa;NODE(){memset(ch,0,sizeof(ch));len=0;}
}dian[N<<1];
int las=1,tot=1;
void add(int c)
{int p=las;int np=las=++tot;dian[np].len=dian[p].len+1;for(;p&&!dian[p].ch[c];p=dian[p].fa)dian[p].ch[c]=np;if(!p)dian[np].fa=1;//以上为case 1else{int q=dian[p].ch[c];if(dian[q].len==dian[p].len+1)dian[np].fa=q;//以上为case 2else{int nq=++tot;dian[nq]=dian[q];dian[nq].len=dian[p].len+1;dian[q].fa=dian[np].fa=nq; for(;p&&dian[p].ch[c]==q;p=dian[p].fa)dian[p].ch[c]=nq;//以上为case 3}}
}
char s[N];int len;
int main()
{scanf("%s",s);len=strlen(s);for(int i=0;i<len;i++)add(s[i]-'a');
}

性质

①endpos:一个子串在原串中所有出现的地方,其末位置下标的集合

如串abcab,endpos(ab)={2,5}

②endpos相同,一个必为另一个后缀,

考虑abcdbcd,当abcd变成后缀bcd的时候,endpos增加,bcd变成cd的时候,endpos不变

③根据②,任意两个子串的endpos集合,要么一个是另一个子集,要么二者相交为空,

只要有一个相交的位置,说明是后缀,后缀就是含于的情况

④根据②,在子串缩短为其后缀的过程中,要么endpos不变,要么增加,把endpos相同的视为一个等价类节点

在SAM中,一个子串只属于一个节点,这个节点内的子串的endpos都相同

⑤endpos等价类(节点)个数为O(n),

这个没看懂曾经看懂过,可以参考原博客

⑥parent树、自动机

后缀自动机的parent树和自动机的节点是共用的,

parent树往祖先跳的时候,endpos会变大,实际上是当前串变为其后缀串,在节点中用fa定义

自动机就是读进这个字符转移到哪个点,定义了一种转移关系,在节点中用ch[0-26]定义,类似trie

⑦由②,不难发现,endpos不变的一段子串是连续的,

分别记minlen和len为这个点对应的子串的最小长度和最大长度

记点a覆盖的串的长度为[minlen(a),len(a)],则从minlen(a)再缩短一个长度的时候,endpos扩充,跳到父亲

所以有len(fa(a))+1=minlen(a),fa(a)是a在parent树上的父亲

⑧后缀自动机的边数为O(n)

这个没看懂曾经看懂过,可以参考原博客

⑨SAM的构造过程

设当前字母为c,从上一个点las转移过来,当前新开一个点np,endpos多出一个{n}来

先考虑转移,为了最大程度的利用节点,

只对las的祖先节点中,计当前祖先节点为p,

若不存在字母c的转移的点,对其进行转移到np的操作,

并令p回跳到p的父亲,最终p停留在了某个节点

以下分三种情况,实际上是(1)(2)两种情况,其中(2)分为两种子情况

(1)c是没出现过的字符,这样回跳的时候一定会回到根,这里计根为1号节点

根代表了空串,其endpos集合为{1,2,...,n},

因此,c所在节点np构成了一个新的endpos集合{n},直接令fa(np)=1

(2)停留在了中途某个点,此时点p存在字母c的转移,所以停下了,

这其中分成两种子情况,计q为p通过字母c能转移到的点,len[q]是q中最长串的长度

①若len[q]=len[p]+1,由于p是las的祖先,p的串一定是las串的后缀,

np比las多了一个字母c,q比p多了一个字母c,且q最长的串是p最长的串的长度+1,

这表明,在p的串后面补一个字母c,其仍然是 在las串后面补一个字母c 的后缀,

则q的串也是np串的后缀,q的endpos一定是np的endpos的超集,令fa(np)=q即可

②len[q]>len[p]+1,由于len[q]>=len[p]+1(是由p的串补了一个字母c而来),既然不等于,就一定大于

说明q中的串分成了两部分,长度=len[p]+1的那些串x,由①,是np串的后缀,其endpos多出了{n}

长度>len[p]+1的那些串y,不是np串的后缀,其endpos没有变化,

而q是np在往上回跳的过程中,第一个包含了np的所有endpos的集合的点,

既然不能表示,就考虑将q拆成两部分,

一部分是x串集合构成的点,是新开的点,记为nq,有len[nq]=len[p]+1

另一部分是y串集合构成的点,保持原来的q不变,

起先,令nq的所有自动机转移关系(所有ch节点)等于原先的q,这样做可行的原因是:

nq是q的后缀,后续在加入新的字符z时,设其跳到状态nr,

由于nq和q只有碰到字母c时有区别,而z不等于c(设z=c,则nr是第一个包含了np的所有endpos的点,与nq是第一个包含了np的所有endpos集合的点矛盾),

故没有受到新字母c的影响,所以二者唯一的区别endpos{n},没有给后续的nr的状态带来影响

然后考虑fa的关系,nq是旧q的一部分,fa(nq)=fa(q),新q比nq长,可以令fa(q)=nq

构建这个nq节点的意义在于表示np,所以令fa(np)=nq

旧q的儿子(转移关系ch)原封不动保留到了新q和nq中,考虑fa的改变

原先有一些节点指向q,但现在nq成为了q和np的fa,这些点应该指向nq,

所以应从p往其祖先回跳,若其碰到字母c的转移为q,就应将其改为nq,

对于没有通过c转移到q的那些祖先节点,其一定指向了nq的祖先,故不用修改

心得

感觉自己死抠知识点的证明,不做题,没啥大的意义,

有些知识点感性理解一下就好了……

但总之思路来源的博主写的很好,

满足了我这个zz对于原理的一切幻想……

去年8月、11月自学过SAM的原理,但是后来没做题,就渐渐忘了,

现在想想,SA前年当时花了四五天抠原理,但现在也只记得rank、sa、height数组是干啥的了,

实际上,SAM的情况就分三种,代码也很短,掌握了性质就可以了……

证明什么的,除了O(n)的点数和边数的证明略复杂以外,剩下的还好……

没必要每次做题前都复习一下证明,更何况这玩意比SA做题直接很多……

后缀自动机(知识整理+板子总结)相关推荐

  1. 区间最值(RMQ)的几种方法(知识整理+板子总结)

    相当于总结一波,以后就从这里扒RMQ的板子 个人觉得博客的这个粘代码背景没我的黑底白字好看QAQ 代码总是越敲越熟的嘛--知识沉积的过程-- 到时候改一改,传参的时候把数组名一起传进去,就能当小黑盒用 ...

  2. 莫队算法(知识整理+板子总结)

    思路来源 Bzoj-2023 小Z的袜子(hose)_ó-CSDN博客(里面还有几篇不错的莫队讲稿) bzoj2038: [2009国家集训队]小Z的袜子(hose)_thy的专栏-CSDN博客 莫队 ...

  3. 洛谷-P3975 弦论(后缀自动机板子题)

    弦论 一道板子题,让我感觉板子题都还不会...然后把递推写成dfs时没有给string加上&,导致内存爆了,2333,果然还是传引用好 题意:求字典序第K小子串以及本质不同的第K小子串 思路: ...

  4. 后缀自动机 (WJMZBMR讲稿的整理和注释)

    链接放在这里,有点难理解,至少我个人是的. 后缀自动机是一种有限状态自动机,其功能是识别字符串是否是母串的后缀.它能解决的问题当然不仅仅是判断是不是后缀这种事,跟字符串的连续子串有关的问题都可以往这个 ...

  5. 【数据结构】自动机全家桶(AC、回文、后缀自动机)

    自动机全家桶 前言 一.AC自动机 1.优秀博客链接 2.问题模板 3.使用 4.本质 5.运用 6.代码模板 二.回文自动机(回文树) 1.优秀博客链接 2.问题模板 3.使用 4.本质 5.运用 ...

  6. Spring AOP 知识整理

    为什么80%的码农都做不了架构师?>>>    AOP知识整理 面向切面编程(AOP)通过提供另外一种思考程序结构的途经来弥补面向对象编程(OOP)的不足.在OOP中模块化的关键单元 ...

  7. 洛谷P3966 [TJOI2013]单词(后缀自动机)

    传送门 统计单词出现次数--为啥大家都是写AC自动机的嘞--明明后缀自动机也能做的说-- 统计出现次数这个就直接按长度排序然后做个dp就好,这是SAM的板子的要求啊,不提了 然后考虑怎么让所有串之间隔 ...

  8. 算法学习:后缀自动机

    [前置知识] AC自动机(没有什么关联,但是看懂了会对后缀自动机有不同的理解) [解决问题] 各种子串的问题 [算法学习] 学习后缀自动机的过程中,看到了许多相关性质和证明,但是奈何才疏学浅(lan) ...

  9. 【USACO06DEC】—牛奶模式Milk Patterns(后缀自动机)

    传送门 后缀自动机板子题了吧 只需要求Parent−TreeParent-TreeParent−Tree上非叶子节点的最长的lenlenlen就可以了 因为字符集太大又不想离散化 就直接用mapmap ...

  10. BZOJ-2780 Sevenk Love Oimaster(广义后缀自动机)

    BZOJ-2780 Sevenk Love Oimaster(广义后缀自动机) 题目链接 题意 给出n个字符串,询问m个串一共出现在几个字符串中. 题解 广义后缀自动机板子题 将n个串建在一起,每次插 ...

最新文章

  1. radio切换控制div显示_React 项目实践——搭建一个温度控制 App
  2. python工作-Python工作五年月薪23K,记录一下我的学习经历建议
  3. iOS 提交应用过程出现的错误及#解决方案#images can't contain alpha channels or transparencies...
  4. Opencv判断是否加载图片的两种方法
  5. Spring系列(三):@ComponentScan注解用法介绍
  6. TCP/IP:IP多播选路
  7. html5语异性元素,异性的5句性暗示
  8. CCPC2018(秦皇岛站)赛后反思
  9. PHP实现简单的计算器
  10. java ajax 进度条_java使用ajax实现进度条
  11. html中半透明效果,CSS半透明效果的属性和场景
  12. 单片机实验板 c语言 打包下载,《AVR单片机开发板 实验板 C语言 视频教程 》
  13. 《请君入瓮——APT攻防指南之兵不厌诈》—第8章8.5节安全贵在未雨绸缪
  14. java jemalloc_jemalloc 快速上手攻略
  15. AdminLTE2的模态框(弹出框)
  16. AHRS算法代码:磁力计+加计+陀螺版
  17. vue webapp之music(六)利用axios与后端接口代理请求歌单推荐数据
  18. 【Ubuntu系列】Ubuntu20.04系统下3060显卡驱动安装记录
  19. 给你的应用程序添加动态鼠标
  20. Android常见内存泄漏及优化总结

热门文章

  1. c语言求三角形周长代码,C语言求三角形面积和周长
  2. 第 22 章 动态属性和特性
  3. 计算机专业群名有内涵,有内涵高大上的群名
  4. Z世代成为消费新主力,我国潮牌营销洞察报告​
  5. 小程序调试技术详解(基于小猴小程序)
  6. 在北大国家发展研究院发言
  7. IE浏览器发送两次相同请求第二次读取第一次缓存问题
  8. 计算几何(圆相关模板) - 2D Geometry 110 in 1! - UVA 12304
  9. 以太网没有有效IP配置问题
  10. 139说客这个产品跟传统的微博和SNS产品的区别