• 后缀自动机应用小结 I


    概念理解与经典类型

    [BZOJ1398] 寻找主人 Necklace

    给定 (S,T),判断其是否循环同构,如果是则输出最小表示。

    直接用 SAM 求最小表示比较是否相等即可。

    [SP7258] SUBLEX

    求给定主串的所有本质不同子串中第 (k) 小子串。

    本质不同子串集合和 SAM 的转移边路径集合构成双射,按拓扑逆序计算每个点发出的路径数,跑 kth 即可。

    [HDU5769] Substring

    求一个串种包含某个特定字符的本质不同子串有多少种。

    设 f[p] 表示从结点 p 出发沿着转移边走能到达的合法的本质不同子串有多少种,设题中要走的字母为 c,对于 p 通过 c 转移到 q,f[p]+=siz[q];对于其它字符,f[p]+=f[q],其中 siz[p] 表示 p 出发可以转移到的本质不同子串数目,按照拓扑逆序统计即可。

    [HDU4436] str2int

    给定若干字符串,每个字符串中所有子串转化为数字,放在一起去重后,求它们的和 (mod 2012)

    如果能处理好前导零那么就是本质不同子串化数求和。将各个数字串用奇怪字符连接起来建立 SAM,对 i 设从根到达它的路径数量为 f[i],它代表的本质不同子串转化为数字后的和为 g[i],对于 i 经过 c 到 j,有 f[j]+=f[i], g[j]+=10g[i]+c*f[i]。为了处理前导零,在根结点转移出去时,跳过 0 转移即可。

    [SP1811] LCS

    求两个字符串的最长公共子串。

    对 A 建立 SAM,将 B 扔到上面跑,记录当前结点 (p) 和匹配长度 (l),能走 trans 边则走,否则沿着 link 跳并让 (l)(len[p])(min),则 (l) 的历史最大值即为答案。

    [LOJ171] 最长公共子串

    求多个字符串的最长公共子串。

    沿用 [SP1811] 的思路,选出最短串建 SAM,对每个节点记录各个串跑时匹配长度的最小值。

    每个串跑时,节点先记录本轮匹配的最大值,再按拓扑逆序上传,最后更新记录的最小值。

    [SDOI2016] 生成魔咒

    按顺序在一个序列的末尾插入数字,求每次插入后的本质不同子串个数。

    后缀自动机增量构造时,已经有的结点的 len 是不会再变化的,而 nq 结点不会产生贡献,于是每次加上 len[last]-len[link[last]] 即可。

    [JSOI2012] 玄武密码

    给定一个基础串 S 和若干询问串 T,对于每个 T 求出其最长前缀 P 满足 P 是 S 的子串。

    SAM 是能接受所有 S 子串的自动机,因此将每个 T 丢上去跑,只能走转移边,走不动时就是答案

    [BJWC2010] 外星联络

    求字符串中出现次数大于 1 的所有本质不同子串的出现次数。

    建出 SAM 后 DFS 并输出 endpos 集合大小。

    [Usaco2006 Dec] Milk Patterns

    给定串 (S) 求出现至少 (k) 次的子串的最大长度。

    出现次数即 endpos 集合大小,基数排序预处理即可。所有满足条件的节点 len 中取最大即可。

    [HDU4622] Reincarnation

    区间询问本质不同子串个数。要求 (O(n^2))

    暴力枚举起点,增量构造,即得到所有区间的答案。(优化做法见后)

    [HDU4416] Good Article Good sentence

    给定 (S) 和若干模式串 (T_i),问 (S) 的子串中有多少不是任何一个 (T_i) 的子串。

    对 S 建立 SAM,(T_i) 跑到 p 时,匹配长度为 l,则该结点及其后缀链接上所有结点所表示的长度 (le l) 的子串都应当被抛弃。考虑对每个结点维护一个匹配过的最大长度 f[i],每次在匹配位置标记,最后按拓扑逆序上传取 max。统计 i 点的答案时,贡献为 len[i]-max(f[i],minlen[i])。

    [BZOJ2780] Sevenk Love Oimaster

    给定若干主串和若干询问,每次询问一个字符串在多少个主串中作为子串出现过。

    对主串构建广义 SAM,求出每个结点在多少个主串中出现过,记为 f[i]。求解时可以暴力沿着后缀链接跳,但为了防止记重同时降低复杂度,需要记录每个结点在本轮中是否被访问过,碰到访问过的就结束。对于询问串扔到自动机上跑,设跑到了 p 则答案为 f[p]。

    [Usaco10Dec] Threatening Letter G

    给定 (s_1,s_2),问至少需要多少个 (s_1) 的子串才能拼接成 (s_2)

    贪心,对 (s_2) 从左到右扫,能分在上一段里必然不会更劣,于是让 (s_2)(s_1) 的 SAM 上贪心地沿着转移边跑,跑不动了就记答案并回到根。

    综合运用

    [BZOJ2555] SubString

    给定一个初始串,支持两种操作:在当前串后面加上一个串;询问一个串在当前串中作为子串出现次数。

    询问即后缀链接树的子树大小,LCT 维护子树大小即可。

    Wannafly Camp 2020 Day 2D 卡拉巴什的字符串

    动态维护任意两个后缀的 (lcp) 集合的 (mex),支持在串末尾追加字符。

    显然答案单调增。LCP 即后缀链接上的 LCA 的 maxlen,一个结点可能成为 LCP 当且仅当它有儿子。修改父子关系时在桶上暴力维护即可。

    [BZOJ1396] 识别子串

    给定 (S),问其每一位的最短识别子串是多长,即包含这个字符且仅出现一次的串。

    建出 SAM,只有 endpos 大小为 1 的结点才有贡献,其范围一定是 [i,pos],对 [pos-minlen+1,pos] 中的每个点产生 minlen 的贡献,对 [pos-maxlen+1,pos-minlen] 中的每个点产生 pos-i+1 的贡献。第一部分线段树直接维护,第二部分线段树维护 f[i]-i 即可。

    [CF149E] Martian Strings

    给定主串 S 和若干询问,每次给定询问串 p,输出有多少个询问串,满足存在 S 的两个不相交的子串拼起来与 p 相等。

    询问串可行当且仅当存在 k 使得 p[1..k] 在主串中的最小结束位置 pre[k] 小于 p[k+1,l] 的最大开始位置 suf[k+1]。对 S 正反串分别建 SAM,通过按拓扑逆序上传预处理每个结点对应的 endpos 集合的最小值。将 p 扔到 SAM 上跑,只走转移边不走后缀链接,即可求出 pre,suf。

    [BZOJ2119] 股市的预测

    寻找 (ABA) 形式的子串数目,满足 (|B|=m)

    枚举 (A) 长度 (i),将 (i,2i,3i,...) 设置为关键点,分别考虑左侧的 (A) 横跨每一个关键点时的情况,由于 (A) 会且仅会横跨一个关键点,这样统计是不重不漏的。设枚举的关键点为 (p),则右侧 (A) 上与之对应的是 (p+i+m),求出这两点的 (lcp,lcs),则左侧 (A) 块可以是区间 ([p-lcs+1,p+lcp-1]),故可能位置有 (lcs+lcp-i) 种。为了不重复,(lcs,lcp) 要对 (i) 取 min。求 (lcs,lcp)(SA)(SAM) 上求 (LCA) 均可。

    [P6292] 区间本质不同子串个数

    区间询问本质不同子串个数。要求 (O(n log^2 n))

    考虑离线,将所有询问挂在右端点上,从左到右扫描整个序列,设扫描到的位置为 (r)。用线段树统计答案,第 i 位表示 S[1..r] 中最后一次出现在左端点为 i 位置的子串数,询问就是求 [l,r] 和。在新增字符 S[r] 时,会对 [1,r] 各产生 1 的贡献,由于某些 S[i..r] 在之前出现,为了去重,用 SAM 维护串,从 S[1..r] 对应节点沿着后缀链接跳,用经过所有节点上一次出现的右端点 lastpos 计算出发生重复的区间 [lastpos[p]-len[p]+1,lastpos-len[fa[p]]],在线段树上 -1,并将 lastpos 设置为 r。考虑到 lastpos 相同的点可以一起处理,每次从当前位置跳到根的过程就是 Access 的过程,用 LCT 维护即可。

    广义 SAM 应用

    [P6139] 【模板】广义后缀自动机

    给定 (s_1,s_2,...,s_n) 求本质不同子串个数。

    广义后缀自动机不只是将 (last) 指回 (root)。建好自动机后像普通 SAM 那样统计答案。

    [ZJOI2015] 诸神眷顾的幻想乡

    给定一棵叶子结点数量 (le 20) 的树,在树上任选一条路径,问有多少种颜色序列不同的选择。

    把每个叶子为根的树 DFS 一遍,当做 Trie 插入广义后缀自动机即可。

    [CF427D] Match & Catch

    求在两个给定字符串中各只出现一次的最短公共子串。

    建立广义 SAM,对每个结点记录来源于各个串的 endpos 集合的大小,如果同为 1 则更新答案。

  • 相关阅读:
    伐木工和森林的故事(一)
    EclipsePDT PHP的开发环境配置
    奇怪的using
    [团队开发]SERVER2008下无法安装VS2008 SP1 和 TFS2008 SP1补丁
    写在七夕
    一点点的松懈,就可以毁掉自己!
    2008,到今天我不后悔
    细节决定成败,注意的事情需要做到,而不是听完了当耳边风
    正视差距,展望2008!
    ZendStudio5.5调式环境配置
  • 原文地址:https://www.cnblogs.com/mollnn/p/13623955.html
Copyright © 2020-2023  润新知