SAM学习小记

前言

只是一个小记,不是算法详解


参考资料

史上最通俗的后缀自动机详解
广义SAM模板题解


正题


概念

定义

简单的,一个有向无环图,边有字母,满足起点开始的每一条路径都是原串的一个子串。
并且保证复杂度在O(n)O(n)O(n)级别内的。

endposendposendpos相关

每一个子串pppendpos(p)endpos(p)endpos(p)被定义为原串中所有出现子串ppp的末尾位置集合。
endposendposendpos相同的子串被定义为一个endposendposendpos类,可以证明任何一个串的endposendposendpos类数量不会超过O(n)O(n)O(n)级别。
性质:

  • 对于两个endposendposendpos相同的子串,其中短的一个一定是另一个的后缀
  • 对于任意两个子串p,qp,qp,q,且qqq的长度大于ppp,一定有endpos(p)⊆endpos(q)endpos(p)\subseteq endpos(q)endpos(p)endpos(q)endpos(p)∩endpos(q)=∅endpos(p)\cap endpos(q)=\varnothingendpos(p)endpos(q)=

parentsparentsparents

根据endposendposendpos的两个性质我们可以构建一棵树,其中对于两个endposendposendposx⊆yx\subseteq yxy那么就有一条边x−>yx->yx>y
性质:

  • 对于一个在faxfa_xfaxendposendposendpos类里的串一定是xxxendposendposendpos类串的后缀
  • 定义在faxfa_xfaxendposendposendpos类里的最长的串长度为LenLenLen,在endposendposendpos类里最短的串长度为lenlenlen那么有Len=len+1Len=len+1Len=len+1

还有一个最重要性质,就是parentsparentsparents里的节点就是SAMSAMSAM里的节点


代码解析

懒得搞图,图片去看参考资料。

void add(int c){int p=las;int np=las=++cnt;len[np]=len[p]+1;siz[cnt]++;for(;p&&!ch[p][c];p=fa[p])ch[p][c]=np;if(!p)fa[np]=1;else{int q=ch[p][c];if(len[p]+1==len[q])fa[np]=q;else{int nq=++cnt;len[nq]=len[p]+1;memcpy(ch[nq],ch[q],sizeof(ch[nq]));fa[nq]=fa[q];fa[np]=fa[q]=nq;for(;p&&ch[p][c]==q;p=fa[p])ch[p][c]=nq;}}return;
}
  • 333行:新节点的最长一定新串的长度,因为左右不可能再加任何节点。
  • 444行:往前跳,中途指一条ccc的边向新节点npnpnp(更新路径上的endposendposendpos)。但是如果一个位置已经有这条边了,前面已经加入过这个字符即有这些新的endposendposendpos了。在parentparentparent树上跳的原因是因为这条链上的endposendposendpos是包含后缀的。
  • 555行:如果字符ccc是新出现的字符,那么这一定是一个由根节点印出来的新endposendposendpos类。
  • 888行:定义新的pppp′p'p,因为p′p'pppp的祖先,且p′p'p中最长的长度加一是ppp中最长的,那么也就是qqq中最长的与npnpnp拥有相同的endposendposendposendpos(np)⊆endpos(q)endpos(np)\subseteq endpos(q)endpos(np)endpos(q)那么npnpnp的父节点就是qqq
  • 10∼1310\sim 131013行:这是SAMSAMSAM中最关键的部分,当lenp+1len_p+1lenp+1不等于lenqlen_qlenq时,那么表示lenqlen_qlenq中不能所有的endposendposendpos都加入nnn,而是有一部分要分离出来。此时我们需要新建立一个节点nqnqnq来储存加入了nnn这个endposendposendposendposendposendpos类。首先加入新字符之前nqnqnqqqq完全相同,所以我们可以直接继承qqq的信息。而因为nqnqnq是可以加入nnn这一信息的,所以有endpos(q)⊆endpos(nq)endpos(q)\subseteq endpos(nq)endpos(q)endpos(nq)所以我们让qqq的父节点为nqnqnq,然后显然npnpnp的父节点也为nqnqnq。然后我们要往前更新信息,如果跳到chp,c≠qch_{p,c}\neq qchp,c=q时,这个节点ppp本身ccc的出边时本身就与qqq没有关系的,所以就可以不用再更新了。

广义SAM

如果一个SAMSAMSAM中我们要加入多个字符串时我们应该怎么办,广义SAMSAMSAM分为离线的和在线的做法。

离线做法:对于所有的字符串我们先构造出一棵TrieTrieTrie树,然后每一次的lastlastlast就是它TrieTrieTrie树上的父节点的节点,因为这样保证了一个节点后面不会插入重复的字符。
在线做法:考虑如果插入了重复的字符怎么办,那么证明这个节点的endposendposendpos类一定是有出现过的,我们可以像SAMSAMSAM中后面那个判断一样搞就好了
这里是在线做法的代码:

ll Ins(ll c,ll last){ll p=last;if(ch[p][c]){ll q=ch[p][c];if(len[p]+1==len[q])return q;else{ll nq=++cnt;len[nq]=len[p]+1;memcpy(ch[nq],ch[q],sizeof(ch[nq]));fa[nq]=fa[q];fa[q]=nq;for(;p&&ch[p][c]==q;p=fa[p])ch[p][c]=nq;return nq;}}ll np=++cnt;len[np]=len[p]+1;for(;p&&!ch[p][c];p=fa[p])ch[p][c]=np;if(!p)fa[np]=1;else{ll q=ch[p][c];if(len[p]+1==len[q])fa[np]=q;else{ll nq=++cnt;len[nq]=len[p]+1;memcpy(ch[nq],ch[q],sizeof(ch[nq]));fa[nq]=fa[q];fa[q]=fa[np]=nq;for(;p&&ch[p][c]==q;p=fa[p])ch[p][c]=nq;}}return np;
}

例题解析

P3804-[模板]后缀自动机

给出一个长度为nnn的串,求一个最大的子串长度乘上子串出现次数

在构造SAMSAMSAM的时候统计每个endposendposendpos类包含了几个endposendposendpos,这就是这个endposendposendpos类子串中出现的次数,然后每个endposendposendpos类取最长的子串就好了(在构造时已经保存了)。
对于每个endposendposendpos的集合如何统计,对于每个npnpnp,它都会有一个前缀iii作为这个endposendposendpos类,而在往下的过程中这个前缀位置iii会丢失(因为再往下的末尾都是在iii之后,而没有一个在iii的后缀是在之后加入的)。也就是让fnp++f_{np}++fnp++,然后按照长度从大到小让ffax+=fxf_{fa_x}+=f_{x}ffax+=fx,因为一个节点的父节点长度一定比子节点小。

P3975-[TJOI2015]弦论

求一个字符串第kkk大的子串。

对于相同的子串算同一个时,那么其实就是求SAMSAMSAM上字典序第kkk大的路径,处理出每一个节点的后继状态直接跑即可。
对于相同的子串不算同一个时,我们处理处每个节点的endposendposendpos集合大小,这就是这个endposendposendpos类中每个子串的出现次数。然后用这个处理后继状态直接跑即可。

SP1811-Longest Common Substring

求两个串的最长公共子串

我们先构建第一个串的SAMSAMSAM,然后用第二个串在第一个串上跑,如果不能继续跑下去那么我们直接在parentparentparent树上往前跳就好了,因为在SAMSAMSAMparentparentparent树的左右可以类似于ACACAC自动机中failfailfail树的定义。然后跳完了之后取len+1len+1len+1就好了。

P5341-[TJOI2019]甲苯先生和大中锋的字符串

求出现次数恰好为kkk的字符串中出现次数最多的长度

因为对于一个相同的endposendposendpos类中的字符串都是长度连续且不同的,也就是[lenfax+1,lenx][len_{fa_x}+1,len_x][lenfax+1,lenx]这个范围内每一个长度各有一个字符串,然后差分做就好了。

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

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

相关文章

【DP】滑雪场的缆车(jzoj 1257)

滑雪场的缆车 jzoj 1257 题目大意 给你一座山的图(有n个间隔相同的点),现在让你从第一个点连到最后一个点,一条线的两个端点的水平距离不能大于m,且线不能通过地面,最多挨着地面,现在问你最少…

小H和游戏

文章目录题目描述题解:传送时间限制:C/C 2秒,其他语言4秒 空间限制:C/C 262144K,其他语言524288K 64bit IO Format:%lld 题目描述 小H正在玩一个战略类游戏,她可以操纵己方的飞机对敌国的N座城市(编号为1~N…

Top Secret Task(dp+滚动数组)

传送门: 题目 dp[i][j][k] 表示 考虑到第i个数 计算前j个数的和 进行了k次操作 则有 若不把第i个数放入前j个数中 dp[i][j][k] dp[i-1][j][k] 若把第i个数放入前j个数中 至少需要把第i个移到第j个,即进行i-j次操作if(k > i-j) dp[i][j][k…

asp.net core 发布到 docker 容器时文件体积过大及服务端口的配置疑问

在 asp.net core 发布时,本人先后产生了3个疑问。1、发布的程序为什么不能在docker容器中运行当时在window开发环境中发布后,dotnet xxx.dll可以正常运行;但放入docker容器后就报 *.*.deps.json not found 的错误。后根据下面的文章解决了问题…

[2020.11.25NOIP模拟赛]出租车【dp】

正题 题面链接:https://www.luogu.com.cn/problem/U142298?contestId37766 题目大意 nnn个人有起点和终点,按顺序上车,但下车可以任意顺序,车最多同时只能载444个人。求车的最短路程。 解题思路 显然我们需要把上次上车的人,现…

纪中B组模拟赛总结(2019.12.21)

(因为是两人一号,所以不方便显示成绩就不打了) 总结: 今天竟有四道题!!! T1看过之后,想了大概10分钟然后想了出来,就是一个单调栈,不算特别难 T2一开始想到…

水题(water)(非详细解答)

传送 时间限制:C/C 1秒,其他语言2秒 空间限制:C/C 32768K,其他语言65536K 64bit IO Format: %lld 题目描述 其中,f(1)1;f(2)1;Z皇后的方案数:即在ZZ的棋盘上放置Z个皇后,使其互不攻击的方案数。…

网络流小结

最大流&#xff1a; EK算法&#xff1a; #include<iostream> #include<cstring> #include<cstdio> #include<queue> using namespace std; const int inf0x7fffffff; const int maxn10010; struct node{int u,v,f,next; }edge[300050]; int s,t,cnt,…

.NET MVC CSRF/XSRF 漏洞

最近我跟一个漏洞还有一群阿三干起来了……背景&#xff1a;我的客户是一个世界知名的药企&#xff0c;最近这个客户上台了一位阿三管理者&#xff0c;这个货上线第一个事儿就是要把现有的软件供应商重新洗牌一遍。由于我们的客户关系维护的非常好&#xff0c;直接对口人提前透…

jzoj5057-[GDSOI2017模拟4.13]炮塔【网络流,最大权闭合图】

正题 题面链接:https://gmoj.net/senior/#main/show/5057 题目大意 n∗mn*mn∗m的网格上有一些炮和敌军&#xff0c;每个炮可以攻击在它方向上一个敌军&#xff0c;但是要求炮弹的轨迹不能交叉。求最多打死多少敌军。 解题思路 我们先把炮分成两类&#xff0c;一类是横着打&a…

【最大流】牛棚安排(jzoj 1259)

牛棚安排 jzoj 1259 题目大意&#xff1a; 有nnn头牛和mmm个牛棚&#xff0c;每头牛有自己第1喜欢&#xff0c;第2喜欢……第mmm喜欢的牛棚&#xff08;开心度分别为m,m−1,m−2……1m,m-1,m-2……1m,m−1,m−2……1&#xff09;&#xff0c;然后读入mmm个数表示第iii个牛棚…

牛客算法周周练2

文章目录A 相反数B Music ProblemC 完全平方数D 小H和游戏E 水题(water)A 相反数 题解 B Music Problem 题解 C 完全平方数 题解 D 小H和游戏 题解 E 水题(water) 题解

讲一下Asp.net core MVC2.1 里面的 ApiControllerAttribute

正文ASP.NET Core MVC 2.1 特意为构建 HTTP API 提供了一些小特性&#xff0c;今天主角就是 ApiControllerAttribute。0. ApiControllerAttribute 继承自 ControllerAttributeASP.NET Core MVC 已经有了ControllerAttribute&#xff0c;这个用来标注一个类型是否是Controller。…

新的UWP和Win32应用程序分发模型

自2005年引入ClickOnce技术以来&#xff0c;.NET就支持应用程序自动升级。在ClickOnce模型中&#xff0c;WinForms和WPF应用程序在启动时会从预先配置好的位置查找新版本。但是&#xff0c;由于微软试图模仿iOS应用商店模型&#xff0c;所以&#xff0c;该模型未能延续到UWP。微…

[2020.11.25NOIP模拟赛]下棋【dp】

正题 题目链接:https://www.luogu.com.cn/problem/U142297?contestId37766 题目大意 nnn个白棋mmm个黑棋排成一排&#xff0c;要求没有任何一段黑白棋的个数差大于ttt。求方案数。 解题思路 设fi,j,k,lf_{i,j,k,l}fi,j,k,l​表示已经摆了iii个白棋jjj个黑棋&#xff0c;所有…

【结论题(QAQ)】SSL新年欢乐赛暨BPM退役赛 A 送分题(luogu U102372)

送分题 luogu U102372 题目大意 你一开始在xxx轴的原点处&#xff0c;现在给你mmm个命令&#xff0c;分别是向左一位和向右一位&#xff0c;对于所有命令&#xff0c;你可以不走也可以按命令走&#xff0c;问你最后你可能在的位置有所少个 输入样例 4 LRLR输出样例 5数据…

牛客网 【每日一题】4月15日 Treepath

文章目录题目描述题解&#xff1a;代码&#xff1a;传送时间限制&#xff1a;C/C 1秒&#xff0c;其他语言2秒 空间限制&#xff1a;C/C 32768K&#xff0c;其他语言65536K 64bit IO Format: %lld 题目描述 给定一棵n个点的树&#xff0c;问其中有多少条长度为偶数的路径。路径…

.net core grpc 实现通信(一)

现在系统都服务化&#xff0c;.net core 实现服务化的方式有很多&#xff0c;我们通过grpc实现客户端、服务端通信。grpc(https://grpc.io/)是google发布的一个开源、高性能、通用RPC&#xff08;Remote Procedure Call&#xff09;框架&#xff0c;使用HTTP/2协议&#xff0c;…

【数学】数列(jzoj 2752)

数列 jzoj 2752 题目大意&#xff1a; 给你一个正整数n&#xff08;有多组数据&#xff09;&#xff0c;让你把它分为一个连续的正整数列之和&#xff08;长度大于1&#xff09;&#xff0c;然你求着个数列最短的长度&#xff0c;如果这个序列不存在&#xff0c;那输出-1 输…

NOIP提高组复赛 知识点整理

枚举、模拟、贪心、递推、排序&#xff08;快排&#xff09; 高精度&#xff1a; 加法&#xff0c;减法&#xff0c;乘法&#xff08;应该只会有高精乘单精&#xff09;&#xff0c;高精度除单精 分治: 二分查找 整体二分 CDQ分治 三分 搜索: dfs、剪枝 bfs、双向bfs 启发式搜索…