基础性质概念

  • 后缀自动机:S的SAM是个DAG,每个节点叫状态,每条带字符ch边表示+ch转移,从开始节点往下,任何一条路径都会对应一个S的子串。

不过为什么要叫"后缀"自动机呢?

  • endpos集合:endpos(s)={s的所有右端点}[s为S的一个子串]
  • 状态(节点):把endpos{}相同的等价类归为一个状态。
  • 边(ch[u][x]):上面定义也说过,状态u中每个s+x集合构成的状态。
  • 推论1:一个等价类中的两个s满足后缀关系。如果不满足,那么存在endpos{}不同。
  • 推论2:由推论1易得等价类中所有s都互相满足前后缀关系而且它们的长度是连续的[l..l+1..r]。假如不连续,存在x,y,z(x是y,z的后缀,y是z的后缀),(endpos简称)ep{x}=ep{z}!=ep{y}所以ep{x}包含ep{y},ep{y}包含ep{z},因此ed{x}=ed{y}=ed{z},与假设矛盾。
  • len[]:表示状态中s最长长度,最短的可以用接下来的变量计算。
  • 推论3:两个等价类的集合要么包含,要么不交,取决与是否有前后缀关系。如果有前后缀关系,len大的那个可以看作len小的那个加一堆前缀很好解释len小包含len大。然后没有后缀关系显然不能有交。

    推论2,3也让我们从后缀角度看待状态。

或许你认为以上就能构成后缀自动机。按照定义来说是的,但是不够。我们还要保证它的状态数和构建操作数为\(O(n)\)

接下来我们会在SAM上连一些虚边,这些虚边会构成有用的fail树

  • par[]:严格包含其ep的最小ep状态点,即par[u]包含的s'是u中s的后缀(而且连续),mnlen[par[u]]=len[u]+1
  • Fail树:father[]为par的一棵树

感性来理解就像某前缀的后缀被分成了很多状态连成一条链。

构建

叫什么增量法,就是在线字符一个一个地加。然后找其最大后缀(par[])。

前提(当前加入第i个,字符为x,这个前缀i的节点为np)

ps.可结合代码理解

首先last为前缀i-1所在的节点。p=last往fail树祖先上跳,同时更新ch[p][x],直到找到一个点ch[p][x]!=0,此时前缀i的最长后缀的长度就是len[p]+1。(因为(在p下面)比len[p]长的后面都没有x)

当然没有这么简单,我们要分三类讨论:

1.没有找到par[],par[np]=rt直接结束

令q=ch[p][x]

2.len[q]=len[p]+1直接par[np]=q

3.len[q]>len[p]+1所代表后缀字符集可以分成两类。长度<=len[p]+1的一类(可以作i前缀(np)的后缀),>len[p]+1的一类跟这次加入无关。

所以容易想到把q拆成两个点,其实拆出1个新点nq(第1类),原来的q(第2类),首先不修改q,用q原来的信息更新nq(par[],ch[][]),len[nq]=len[p]+1,然后更新par[q]=par[p]=nq(Fail树中把q,np连在nq下)。

最后容易遗忘的是p及其上面一些点(因为len[nq]=len[p]+1)原来ch[p][x]=q现在改为ch[p][x]=nq了。

复杂度

可以看看别人的博客

不会证耶?有会证的而且证的很简单的私信我?

code

点击查看代码
struct SAM {
int ch[N][27],t[N],len[N],lst,num,par[N],sz[N];
SAM() {lst=num=1;}
int Insert(int x) {
int p=lst,np=++num;lst=np;len[np]=len[p]+1;sz[np]=1;
for(;!ch[p][x];p=par[p]) ch[p][x]=np;
if(!p) {par[np]=1;return np;}
int q=ch[p][x];
if(len[q]==len[p]+1) {par[np]=q;return np;}
int nq=++num;par[nq]=par[q];len[nq]=len[p]+1;
for(int j=0;j<26;j++)ch[nq][j]=ch[q][j];
par[q]=par[np]=nq;
for(;ch[p][x]==q;p=par[p])ch[p][x]=nq;
return np;
}
}A;

用途(例题)

匹配字符串:

不用说了所有自动机(dfn)都能做的事情

多少个本质不同的字符串(位置不同串相同算同一个)

\(ans= \sum len[u]-len[fa[u]]\)每个(本质不同)字符串都唯一对应与SAM中的节点,而SAM中不同节点表示的字符集没有交集。因此就是每个节点u表示的字符个数(len[par[u]]-len[u])的和。

每个字符串出现了几次

Fail树上,每个节点\(sz[par[u]]+=sz[u]\),每个前缀对应节点(\(sz[np]=1\))

其实sz[u]就是ep等价类u中字符串对应的出现次数了

证明?

把前缀np,sz[np]=1,实际上它会给所有它的后缀+1,然后每个节点对应等价类的ep{r1,r2,r3..rk},显然sz=k。其中每个都会被前缀r1,前缀r2..前缀rk+1各+1。所以刚好+k次,得证。

SAM[详细~bushi]的更多相关文章

  1. sam格式详细说明

    原文链接 https://www.jianshu.com/p/386f520e5de1 The SAM Format Specification(sam格式说明) 1 The SAM Format S ...

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

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

  3. Linux中find、grep命令详细用法

    在linux下面工作,有些命令能够大大提高效率.本文就向大家介绍find.grep命令,他哥俩可以算是必会的linux命令,我几乎每天都要用到他们.本文结构如下: find命令 find命令的一般形式 ...

  4. 初创互联网公司简明创业指南 - YC新掌门Sam Altman

    本文只是一个创业指南的简明版 - 更详细的版本请查看:http://startupclass.samaltman.com 创业之前,你更应该去拥有一个好的创意,而不是一个公司.如果开始前你拥有一个好的 ...

  5. SAMTOOLS使用 SAM BAM文件处理

    [怪毛匠子 整理] samtools学习及使用范例,以及官方文档详解 #第一步:把sam文件转换成bam文件,我们得到map.bam文件 system"samtools view -bS m ...

  6. Luogu P3181 [HAOI2016]找相同字符 广义$SAM$

    题目链接 \(Click\) \(Here\) 设一个串\(s\)在\(A\)中出现\(cnt[s][1]\)次,在\(B\)中出现\(cnt[s][2]\)次,我们要求的就是: \[\sum cnt ...

  7. SAM文件格式

    帮朋友处理sam各式文件,又记不住sam各式每列代表的什么内容,干脆转个帖子留着以后查询. 在SAM输出的结果中每一行都包括十二项通过Tab分隔,从左到右分别是: 1 序列的名字 2 概括出一个合适的 ...

  8. 后缀自动机(SAM)速成手册!

    正好写这个博客和我的某个别的需求重合了...我就来讲一讲SAM啦qwq 后缀自动机,也就是SAM,是一种极其有用的处理字符串的数据结构,可以用于处理几乎任何有关于子串的问题,但以学起来异常困难著称(在 ...

  9. 【H3C交换机】cpu各个进程的详细说明

    display cpu-usage命令用来查看设备CPU占用率的统计信息,以及各个进程的cpu占用率. 各个进程详细说明如下,不同软件版本.盒式和框式的cpu进程略有不同,详细信息可以查看手册中的命令 ...

随机推荐

  1. VasSonic Android源码解析

    VasSonic是腾讯推出的为了提高H5页面首屏加载速度而推出的高性能Hybrid框架,目前广泛应用在QQ商城等Hybrid界面中,以提高用户体验. https://github.com/Tencen ...

  2. prometheus之查询语言

    PromQL(Prometheus Query Language)是 Prometheus 自己开发的表达式语言,语言表现力很丰富,内置函数也很多.使用它可以对时序数据进行筛选和聚合. 一.PromQ ...

  3. java中内部类中还有内部类请给实例!

    2.当内部类中还有一个内部类,下面给出了一个实例.[新手可忽略不影响继续学习](以下多出代码, 用蓝色标记)例2.2:class ShellMark_to_win {    int shell_x = ...

  4. in a frame because it set 'X-Frame-Options' to 'sameorigin'

    不是所有网站都给  iframe嵌套的,  有的网站设置了  禁止嵌套!!! 浏览器会依据X-Frame-Options的值来控制iframe框架的页面是否允许加载显示出来, 看你们公司这么设置了!! ...

  5. 实现一个promise.all方法

    思路: 1:首先明白all的用法 2:promise.all可以接受一个由promise数组作为参数,并且返回一个promise实例, 3:promise.all([a,b,c...]).then方法 ...

  6. python---二分查找的实现

    from cal_time import get_running_time @get_running_time def bin_search(li, val): """ ...

  7. go sync.map源码解析

    go中的map是并发不安全的,同时多个协程读取不会出现问题,但是多个协程 同时读写就会出现 fatal error:concurrent map read and map write的错误.通用的解决 ...

  8. EntityFramwork常见问题

    1.常用的语句有哪些 添加migration      dotnet ef migrations add [MIgrationName] 删除刚添加的migration      dotnet ef ...

  9. zookeeper篇-zookeeper客户端和服务端的基础命令

    点赞再看,养成习惯,微信搜索「小大白日志」关注这个搬砖人. 文章不定期同步公众号,还有各种一线大厂面试原题.我的学习系列笔记. 前提:我把zookeepee安装在了服务器/usr/local/java ...

  10. 攻防世界-MISC:坚持60s

    这是攻防世界新手练习区的第六题,题目如下: 点击附件1下载,是一个java文件,点击运行一下: 绿帽子满天飞不知道是怎么回事(还是老老实实去看WP吧),WP说这是编译过的Java代码,但我手里没有反编 ...