讲解一些 SAM 经典的应用。可以结合 字 符 串 全 家 桶 中 SAM 的部分食用。

洛谷P2408

求不同子串个数。在 SAM 中,所有结点是一个等价类,包含的字符串互不相同。结点 \(u\) 中包含的子串数目就是 \(\text{len}(u)-\text{len}(\text{slink}(u))\),对所有结点求和即可。

洛谷P3804

丢到 SAM 上,会发现是要求每个结点的 \(\text{endpos}\) 大小。这个值等于它在 \(\text{parent}\) 树上子树内前缀结点的数目。前缀结点就是那些包含了整个字符串的某个前缀的结点。事实上,一个结点的 \(\text{endpos}\) 集合就是它子树内所有前缀结点的位置的集合。如果直接建出树来常数较大,可以按照 \(\text{len}\) 排序从大到小贡献,使用基数排序。

洛谷P4070

动态不同子串个数。考虑一次插入对答案的影响:

  • 如果只新建了一个结点,也就是前两个 case,这时原有结点的 \(\text{slink}\) 都没有修改,所以只用加上 \(\text{len}(cur)-\text{len}(\text{slink}(cur))\);
  • 如果新建了两个结点,也就是第三个 case,此时 \(q\) 的 \(\text{slink}\) 跑到了 \(r\) 上,\(r\) 的 \(\text{slink}\) 又等于 \(q\) 原来的 \(\text{slink}\),一进一出相当于没有变化,所以也只用加上 \(\text{len}(cur)-\text{len}(\text{slink}(cur))\)。

其实也很好理解,表示整个串的结点的 \(\text{endpos}\) 当然就是 \(\{n\}\),也就包含了所有新出现的子串。

另外这题范围很大,需要用 map 记转移。

CF235C

一个串循环发生了什么变化?删除开头字符,加上结尾字符。而这两个操作都是容易在 SAM 上完成的。后者就是自动机的转移,而前者只需要检查长度然后判断是否需要跳到 parent tree 上的父亲结点即可。具体到这道题上,我们相当于把询问串读入两遍,对每个前缀找到能够匹配的最长后缀,要求这个后缀的长度不超过询问串的长度。右移一位时,如果刚才匹配到了就先删除开头字符,然后再尝试加上结尾字符,如果不行就跳父亲。

洛谷P6640

这题更加直接的展示了 SAM 容易删除开头字符的特性:我们可以对每个 \(i\) 求出 \(s[1\cdots i]\) 出现在 \(t\) 中的最长后缀。具体地,在自动机上维护一个指针,表示当前的后缀。加入字符时,不断跳 parent 树上的父亲直到存在转移。求出这个最长后缀 \(f_i\) 后,对每个询问二分答案,在 ST 表上查询区间最大值即可。

SPOJ-JZPGYZ

这道题需要使用广义 SAM。可以在每两个字符串之间加特殊字符,或者直接在处理完每个字符串之后把 lst 置 \(0\)。给每个字符串的前缀位置染色,对于每个询问,找到这个字符串在广义 SAM 上对应的结点(如果不存在则答案为 \(0\)),然后答案就就是这个结点子树内的颜色数目。离线二维数点。

洛谷P3346

这一题同样需要广义 SAM。事实上上一题提到的两种 SAM 应当称为“伪广义 SAM”,它们可能会产生空结点。标准的广义 SAM 需要先建出 Trie 树,然后 BFS 遍历整棵树,记录下加入 Trie 树上每个结点之后 SAM 的 pos,每个结点就在父亲结点的 pos 基础上加入。回到本题,先对于每个叶子结点遍历一遍全树,建立 Trie 树,然后建出广义 SAM 求解即可。

CF653F

感觉做法有点抽象。仍然是建出 SAM。对于 SAM 的每个结点,取它 endpos 集合里的一个右端点,把这个长度区间丢到这个右端点上。然后对于每个右端点 \(r\),一个合法的左端点 \(l\) 要求前缀和 \(s_{l-1}=s_r\),且 \(s_r\) 是 \([l,r]\) 的最小值。对于后者可以倍增,对于前者可以拆成两个询问,离线,然后扫描一遍开桶统计。

CF1037H

建出字符串 \(S\) 的 SAM。对于一个询问串 \(T\),字典序大于它的最小字符串一定是 \(T\) 的某个前缀 \(T_{1\cdots i}\) 加上一个大于 \(T_{i+1}\) 的字符。那么在 SAM 上找到 \(T_{1\cdots i}\) 对应的结点,遍历它大于 \(T_{i+1}\) 的出边,就只要判断到达的结点的子树内是否包含了一个 \([L+i,R]\) 内的前缀结点。这可以用可持久化线段树维护 DFS 序实现。

SPOJ-REPEATS

这是一个 border 相关的问题。我们发现,如果一个串同时出现在两个位置,设这两个位置的差为 \(d\),这个串的长为 \(len\),则一定有一个字符串连续重复出现 \(\lfloor\frac{len}{d}\rfloor+1\) 次,也就是开头不重叠的那一部分。所以只要求出每个点 endpos 集合内差的最小值即可。用线段树合并实现。

CF666E

这道题用到 SAM 的技巧是:要多次在模式串上匹配一个串的某个区间时,可以预处理出每个位置的最长匹配后缀,然后倍增跳 parent tree。剩下的就是一个线段树合并。

Solution Set - SAM的更多相关文章

  1. BZOJ3926:[ZJOI2015]诸神眷顾的幻想乡(广义SAM)

    Description 幽香是全幻想乡里最受人欢迎的萌妹子,这天,是幽香的2600岁生日,无数幽香的粉丝到了幽香家门前的太阳花田上来为幽香庆祝生日. 粉丝们非常热情,自发组织表演了一系列节目给幽香看. ...

  2. BZOJ.3998.[TJOI2015]弦论(后缀自动机)

    题目链接 \(Description\) 给定字符串S,求其第K小子串.(若T=0,不同位置的相同子串算1个:否则算作多个) \(Solution\) 建SAM,处理出对于每个节点,它和它的所有后继包 ...

  3. 【刷题】BZOJ 2555 SubString

    Description 懒得写背景了,给你一个字符串init,要求你支持两个操作 (1):在当前字符串的后面插入一个字符串 (2):询问字符串s在当前字符串中出现了几次?(作为连续子串) 你必须在线支 ...

  4. 【刷题】BZOJ 3998 [TJOI2015]弦论

    Description 对于一个给定长度为N的字符串,求它的第K小子串是什么. Input 第一行是一个仅由小写英文字母构成的字符串S 第二行为两个整数T和K,T为0则表示不同位置的相同子串算作一个. ...

  5. 【刷题】SPOJ 8222 NSUBSTR - Substrings

    You are given a string S which consists of 250000 lowercase latin letters at most. We define F(x) as ...

  6. SAM初探

    SAM,即Suffix Automaton,后缀自动机. 关于字符串有很多玩法,有很多算法都是围绕字符串展开的.为什么?我的理解是:相较于数字组成的序列,字母组成的序列中每个单位上元素的个数是有限的. ...

  7. BZOJ4327:[JSOI2012]玄武密码(SAM)

    Description 在美丽的玄武湖畔,鸡鸣寺边,鸡笼山前,有一块富饶而秀美的土地,人们唤作进香河.相传一日,一缕紫气从天而至,只一瞬间便消失在了进香河中.老人们说,这是玄武神灵将天书藏匿在此.  ...

  8. 【洛谷4070】 [SDOI2016]生成魔咒(SAM)

    传送门 洛谷 Solution 考虑要求的是什么,前缀的本质不同的字符串个数? 如果只要求一个串那么显然答案是\(\sum_{i=1}^{tot}len[i]-len[fa[i]]\)(实际上这个并不 ...

  9. 【BZOJ3676】 [Apio2014]回文串(SAM,manacher)

    传送门 BZOJ 洛谷 Solution 考虑我们每找到一个回文串就更新一次答案,跑个SAM,这样子复杂度是爆炸的. 接下来的就是优化: 我们可以倍增跳直到跳不了,最后的siz就是出现次数. 没了?没 ...

  10. 【BZOJ3238】 [Ahoi2013]差异(SAM)

    传送门 BZOJ 洛谷 Solution SA版本的 考虑可以建一个SAM? 那么接下来我们就考虑每一对点对之间的贡献了. 把这个式子化简一下就是无序点对之间的那啥(自己意会一下) 然后我们定义边权为 ...

随机推荐

  1. WPF实现树形表格控件(TreeListView)

    前言 本文将探讨如何利用WPF框架实现树形表格控件,该控件不仅能够有效地展示复杂的层级数据,还能够提供丰富的个性化定制选项.我们将介绍如何使用WPF提供的控件.模板.布局.数据绑定等技术来构建这样一个 ...

  2. Arm架构下麒麟操作系统安装配置Mariadb数据库

    1.安装配置JDK (1)检查机器是否已安装JDK 执行 java -version命令查看机器是否安装JDK,一般麒麟操作系统默认安装openjdk 1.8. (2)安装指定版本JDK 如果麒麟操作 ...

  3. OpenHarmony 官网文档有哪些上新?上篇:应用开发文档上新

    随着 OpenAtom OpenHarmony(以下简称"OpenHarmony")系统能力持续升级,已具备支撑复杂带屏标准设备和应用开发的基础能力.相较于旧版本,OpenHarm ...

  4. Java 继承与多态:代码重用与灵活性的巧妙结合

    Java 继承(子类和超类) 在 Java 中,可以从一个类继承属性和方法到另一个类.我们将"继承概念"分为两类: 子类(child): 从另一个类继承的类 超类(parent): ...

  5. SQL LIKE 运算符:用法、示例和通配符解释

    SQL中的LIKE运算符用于在WHERE子句中搜索列中的指定模式.通常与LIKE运算符一起使用的有两个通配符: 百分号 % 代表零个.一个或多个字符. 下划线 _ 代表一个单个字符. 以下是LIKE运 ...

  6. Go 语言注释教程

    注释是在执行时被忽略的文本.注释可用于解释代码,使其更易读.注释还可用于在测试替代代码时防止代码执行.Go支持单行或多行注释. Go单行注释 单行注释以两个正斜杠(//)开头. 在//和行尾之间的任何 ...

  7. MogDB/OpenGauss数据库中通过参数控制抓取慢sql

    MogDB/OpenGauss 数据库中通过参数控制抓取慢 sql 本文出处:https://www.modb.pro/db/221556 mogdb 数据库中可以通过打开相应的参数抓取慢 sql,该 ...

  8. HTTP 使用指南

    0x1 初识 HTTP 协议 网页加载流程 graph LR A(user 输入网址)==>B(browser 进程) B==>C(处理输入信息) B-->D(页面加载完成) C== ...

  9. redis 简单整理——bitmaps[十二]

    前言 简单介绍一下bitmaps这个东西. 正文 我们都知道bitmaps 翻译过来就是二进制. 那么二进制可以存一些什么呢? 图片.视频,还可也存些什么呢? 现代计算机用二进制(位)作为信息的基础单 ...

  10. docker 应用篇————docker开篇[一]

    前言 因为最近看了一些docker 底层,然后希望把docker应用先编写出来,然后进行细节篇讲解,比如说docker 的底层是如何实现的之类的话题. 正文 docker 这东西怎么说呢?有一些东西需 ...