模板:后缀自动机(SAM)

所谓后缀自动机,就是通过后缀建立的自动机

(逃)
请允许我先介绍一下后缀家族:
在这里插入图片描述
(又逃)

前言

OI生涯目前为止学习的最为难以理解的算法,没有之一。
到现在也没有完全的理解。
qwq

概念

定义:

后缀 iii :字符串 sssiii 结尾的后缀(前缀同理)
endpos(x)endpos(x)endpos(x) 字符串 xxxsss 中出现的结尾位置的集合
等价类:若 endpos(u)=endpos(v)endpos(u)=endpos(v)endpos(u)=endpos(v),我们就称 uuuvvv 属于同一个等价类

不难发现,对于 sss 的一个子串 x=sl...rx=s_{l...r}x=sl...r,都存在一个位置 p∈(l,r]p\in (l,r]p(l,r],满足对于 l≤i≤pl\le i\le plipxxx 的后缀 iii 都与 xxx 属于同一个等价类,而对于 p<i≤rp<i\le rp<ir,后缀 iiixxx 都不属于一个等价类。
我们称满足这个性质的 ppplink(x)link(x)link(x)

SAM是一个字符转移边组成的DAG,每条从根结点出发的路径都唯一对应 sss 的一个子串,在SAM中,每个结点都对应着一个等价类的集合(也就是从根结点到该结点的路径所代表的字符串的集合,这些字符串必然由一个最长的字符串和它的一些连续的后缀组成),一个结点的 linklinklink 定义为该结点对应的最长字符串的 linklinklink

请务必确保你理解了上面这段话

构建

现在考虑如何构建出SAM
使用增量法,当前加入一个新的字符串 ccc
设上一个加入的结点为 lstlstlst,当前加入结点为 curcurcur
设一个结点代表的最长字符串的长度为 lenlenlen

首先,令 len(cur)←len(lst)+1len(cur)\gets len(lst)+1len(cur)len(lst)+1
然后从 lstlstlst 沿着 linklinklink 不断往上跳,直到跳到某个有 ccc 的转移边或者跳到根为止,沿途把 ccc 的转移边全部赋值成 curcurcur

situation 1

若到根了还没有 ccc 的转移边:说明整个字符串还没有出现过 ccc,直接把 link(cur)link(cur)link(cur) 赋值成根即可

否则,设跳到了结点 ppppppccc 转移边为 qqq
由于一直跳的是

situation 2

len(q)=len(p)+1len(q)=len(p)+1len(q)=len(p)+1:这两个结点在原串上就是相邻的,直接令 link(cur)=link(q)link(cur)=link(q)link(cur)=link(q) 即可

situation 3

len(q)≠len(p)+1len(q)\ne len(p)+1len(q)=len(p)+1:这两个结点在原串上不是相邻的,此时若按照情况2的处理方法,会使SAM上出现不应该出现的前缀,所以我们应该分裂出一个结点 pppppp,继承所有 qqq 的信息,len(pp)←len(p)+1len(pp)\gets len(p)+1len(pp)len(p)+1,并把 qqqcurcurcurlinklinklink 全指向 pppppp,再一路往上把本来连向 qqq 的转移连向 pppppp

代码

void ins(int c){c-='a';int cur=++tot,p=lst;lst=tot;st[cur].len=st[p].len+1;siz[cur]=1;for(;p&&!st[p].tr[c];p=st[p].fa) st[p].tr[c]=cur;if(!st[p].tr[c]) st[cur].fa=1;else{int q=st[p].tr[c];if(st[q].len==st[p].len+1) st[cur].fa=q;else{int pp=++tot;st[pp]=st[q];st[pp].len=st[p].len+1;st[q].fa=st[cur].fa=pp;for(;p&&st[p].tr[c]==q;p=st[p].fa) st[p].tr[c]=pp;return;}}
}

应用

求 endpos 集合大小

定义 sizxsiz_xsizx 为结点 xxx 的等价类集合中 endposendposendpos 的数目。(也就是出现次数)
那么根据定义,有:
sizx=∑s∈sonxsizs+[x∈S]siz_x=\sum_{s\in son_x} siz_s+[x\in S]sizx=ssonxsizs+[xS]
其中 SSS 是每次插入的终点集合
dfs或者拓扑实现均可

int cnt[N],id[N];
void calc(){for(int i=1;i<=tot;i++) ++cnt[st[i].len];for(int i=1;i<=n;i++) cnt[i]+=cnt[i-1];for(int i=tot;i>=1;i--) id[cnt[st[i].len]--]=i;for(int i=tot;i>=1;i--) siz[st[id[i]].fa]+=siz[id[i]];return;
}

求本质不同子串数

就是在自动机上的走法种类呗。
那么就有:
sumx=∑s=trx,csums+1sum_x=\sum_{s=tr_{x,c}}sum_s+1sumx=s=trx,csums+1

Thanks for reading!

后缀树

本身也是一个大算法,但是可以通过反串建SAM偷懒。
复杂度为 O(nC)O(nC)O(nC)

解析

对反串建出后缀自动机,其 failfailfail 树即为所求的后缀树。
plxpl_xplx,为 xxx 节点对应的任意一个出现位置,那么 failx→xfail_x\to xfailxx 这条边上对应的字符串就是 s(plx+lenfailx,plx+lenx−1)s(pl_x+len_{fail_x},pl_x+len_x-1)s(plx+lenfailx,plx+lenx1)
结合 failfailfail 的定义应该不难得到。

后缀树的性质:

  1. 根到叶子的路径和所有后缀一一对应。
  2. 所有非根节点都至少有两个子节点。
  3. LCP(i,j)LCP(i,j)LCP(i,j) 就是两个位置对应节点 lca 的最长长度。

在解决字典序相关问题时较为常用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/317263.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

.NET 开源项目 Anet 介绍

使用 Anet 有一段时间了&#xff0c;已经在我的个人网站&#xff08;如 bookist.cc&#xff09;投入使用&#xff0c;目前没有发现什么大问题&#xff0c;所以才敢写篇文章向大家介绍。GitHub 地址&#xff1a;https://github.com/anet-team/anetAnet 是一个 .NET Core 通用框架…

线性代数问卷调查反馈——Find The Determinant III,Takahashi‘s Basics in Education and Learning

文章目录Find The Determinant IIIsourcecodeTakahashis Basics in Education and LearningsourcecodeFind The Determinant III source 高斯消元求行列式的模板题 code #include <cstdio> #include <iostream> using namespace std; #define maxn 205 #define…

L - Who is the Champion

L - Who is the Champion 计蒜客 - 42587 题意&#xff1a; 给出一个N阶矩阵&#xff0c;&#xff08; i , j &#xff09; &#xff08;i, j&#xff09;&#xff08;i,j&#xff09;处的数字表示这场比赛球队i ii踢进球队j jj多少球。两支球队平局则各加一分&#xff0c;一…

CF1037H Security(SAM)

解析 算是一个比较高级的SAM的应用了 对fail树的dfs序建立维护右端点最大值的线段树 考虑把所有的询问离线&#xff0c;按照右端点排序 每次动态把当前询问右端点左侧的前缀插入线段树 处理询问时&#xff0c;先贪心的尝试和询问串填法一样&#xff0c;如果不行就往下一个字母…

AT5147-[AGC036D]Negative Cycle【dp,模型转换】

正题 题目链接:https://www.luogu.com.cn/problem/AT5147 题目大意 有nnn个点的一张图&#xff0c;其中i→i1(i<n)i\rightarrow i1(i< n)i→i1(i<n)有一条边权值为000。 对于其他i,j(i≠j)i,j(i\neq j)i,j(ij)存在一条边i→ji\rightarrow ji→j&#xff0c;若i&l…

栈/队列/分块问卷调查反馈——Weak in the Middle,Cutting Plants,最小公倍数

文章目录Weak in the MiddlesourcesolutioncodeCutting Plantssourcesolutioncode[HNOI2016]最小公倍数sourcesolutioncodeWeak in the Middle source solution 栈模拟。 天数的计算&#xff0c;可以发现与其参与三元比较的次数有关 对于栈顶&#xff0c;如果被弹出&#…

我的十年创业路

记十年创业的心路历程和我的创业思辨导读1 为什么写这篇文章2 详细的总结和思辨 2.01 感恩 2.02 为什么创业 2.03 十年流水账 2.04 经历了哪些失败 2.05 重要的职场基础 2.06 持续的学习和进步 2.07 创业与兴趣 2.08 价值观的碰撞和选择 2.09 合作与…

C - And and Pair

C - And and Pair 题意&#xff1a; 问有多少组(i,j)满足要求。 要求为&#xff1a; 0<j<i<n i&ni i&j0 答案mod 1e97 题解&#xff1a; 这个和我的思路时一样的&#xff0c;且讲的更清楚 i&ni说明n为0的地方&#xff0c;i必须为0&#xff1b;n为1的地…

CF850F Rainbow Balls(数学、期望)

解析 二倍相邻项&#xff0c;就要想裂项 纯数学题 一道黑色的小凯的疑惑 设总球数为 sss 我们先钦定一种颜色留到最后&#xff0c;那么其他颜色可以等价考虑 设 fif_{i}fi​ 为钦定的颜色的球有 iii 个&#xff0c;涂完需要的期望次数 则有&#xff1a; fi(fi−1fi1)pfi(1−2p…

pjudge#21652-[PR #4]到底有没有九【数位dp】

正题 题目链接:http://pjudge.ac/problem/21652 题目大意 给出一个正整数kkk&#xff0c;求第nnn个xxx满足x(10k−1)x\times (10^k-1)x(10k−1)中没有一个数位为999。 1≤n≤1018,1≤k≤181\leq n\leq 10^{18},1\leq k\leq 181≤n≤1018,1≤k≤18 解题思路 首先是从高位到低…

专题突破二之优先队列、st表——,Running Median,Sequence,Buy Low Sell High,数据备份,超级钢琴,ZQC的手办

文章目录Running MedianSequenceBuy Low Sell High[APIO/CTSC 2007] 数据备份[NOI2010] 超级钢琴「LibreOJ β Round」ZQC 的手办Running Median source 对顶栈 用大根堆和小根堆一起维护 若元素小于等于大根堆栈顶&#xff0c;放入大根堆否则放入小根堆 大根堆维护的就是…

G - Eating Plan

G - Eating Plan 题意&#xff1a; 一个1到n组成的排列&#xff0c;每个数的价值为其阶乘&#xff0c;有m个询问ki&#xff0c;要求你在排列中选取连续的一块&#xff0c;使得价值和mod 998857459 后&#xff0c;大于ki&#xff0c;问最短区间长度&#xff0c;如果不存在输出…

P4770:你的名字(SAM、线段树合并)

文章目录前言解析前言 1000A快乐&#xff01;&#xff01;&#xff01;awa 没有想象中的那么恶心。 解析 先考虑每次都询问 [1,n][1,n][1,n] 如何做。 正难则反&#xff0c;用T所有本质不同串数量减去是S串子串又是T的子串的数量 前者很好求&#xff0c;关键是后者 首先可以…

DotNetty 实现 Modbus TCP 系列 (一) 报文类

Modbus TCP/IP 报文报文最大长度为 260 byte (ADU 7 byte MBAP Header 253 byte PDU)Length Unit Identifier 长度 PDU 长度MBAP HeaderPDUPDU 由两部分构成&#xff1a;Function Code(功能码) 和 Data 组成Function Code部分功能码&#xff1a;报文类ModbusHeaderModbusHe…

AT2377-[AGC014E]Blue and Red Tree【启发式合并】

正题 题目链接:https://www.luogu.com.cn/problem/AT2377 题目大意 有两棵树T1,T2T_1,T_2T1​,T2​。T1T_1T1​树上的边开始时都是蓝色的&#xff0c;我们每次选择一条蓝色边路径(x,y)(x,y)(x,y)&#xff0c;然后删掉路径上一条边&#xff0c;连接一条xxx到yyy的红色边。 要…

B - A Funny Bipartite Graph

B - A Funny Bipartite Graph 题意&#xff1a; 一个二分图&#xff0c;左右各有n个点&#xff0c;左边第i个点有一个属性mi&#xff0c;它在一个图中的价值为midi,其中di为它在图中的度数(特殊的&#xff0c;如果度数为0&#xff0c;则价值为0)&#xff0c;求一个该二分图的…

专题突破三之并查集Ⅰ——Portal,parity,食物链,程序自动分析,Almost Union-Find,洞穴勘测

文章目录Portalparity[NOI2001] 食物链程序自动分析UVA11987 Almost Union-Find[SDOI2008] 洞穴勘测Portal source 百度翻译简直就是个鬼…(((m -__-)m 离线 将边和询问按权值排序&#xff0c;指针&#xff0c;将所有权值不超过当前询问iii的边全加进去 答案路径自然是不连…

C# 未来新特性:静态委托和函数指针

C# 每发布一次新版本&#xff0c;都会增加一些底层相关的新特性&#xff0c; 这些特性对大多数商业程序来说并没什么实际用处&#xff0c;主要用于那些对性能有很高要求的代码&#xff0c;如图形处理、机器学习以及数学工具包&#xff0c;等等。接下来的两个提案&#xff0c;主…

CF700E Cool Slogans(SAM,dp)

解析 好题。 首先&#xff0c;我们每次都令 sis_isi​ 是 si1s_{i1}si1​ 的后缀&#xff0c;肯定是不劣的 问题就可以转化到 fail 树上了 首先肯定要线段树合并处理出endpos集合 朴素想法&#xff1a;设父亲 fafafa 的结束位置为 posfapos_{fa}posfa​&#xff0c;若 [posfa−…

pjudge#21651-[PR #4]猜猜看【交互】

正题 题目链接:http://pjudge.ac/problem/21651 题目大意 有一个1∼n1\sim n1∼n的排列&#xff0c;每次你可以询问 iii和jjj的大小关系i,j,ki,j,ki,j,k的中位数 现在要求在222次111操作和2n2n2n次222操作内得到这个排列。 50≤n≤510550\leq n\leq 5\times 10^550≤n≤5105…