关于SAM和广义SAM

关于SAM和广义SAM

不是教程

某些思考先记下来

SAM

终于学会了这个东西诶......

一部分重要性质

确定一个重要事情,S构造出的SAM的一个重要性质是当且仅当对于S的任意一个后缀,可以从1号节点走到终止状态。专业的名词叫做有限状态自动机。

trans[st][c]表示的是对于状态st,如果将st中任意串s加一个c,那么会到达的新状态new,显然new是唯一的。假如不唯一那么s一定不属于同一个st。

fa[st]表示的是对于状态st,如果慢慢缩小st中后缀长度,会到达的第一个状态。规定一个虚点\(1\)全集,那么fa能够构成一个树形结构(parent tree)。

很显然\(endpos[st]\subset endpos[fa[st]]\)。所以虽然\(\sum|endpos|=O(n^2)\)但是可以通过线段树合并得到endpos集合。你也可以发现Parent Tree任何一个到根的链是一个长度递减且连续的某个后缀的前缀。

trans构成的有向图G一定是一个DAG,因为可以建立这个图从1到任意点的路径构成的串对应的原串,所以有环就出大事了。

G上任意一条从1开始走的路径都代表一个后缀的前缀——也就是一个子段。

而对于G任意一个i节点开始走的路径,表示的是对于后缀i的任意一个子段。

可以发现一个确定的Parent Tree和Trans[][]可以唯一确定一个串和SAM的形态。

构建和复杂度证明

先说构建,构建的目的是要让这个东西能够识别新的后缀并且还要维持好Parent Tree的各种性质。

设原来是S[1...r]现在我们要变成S[1...r+1],

首先可以发现的事情是,新状态一定包括\(S[1....r+1]\),设这个新状态为u,那么首先我们要让所有\(S[i...r+1]\)都被表示出来,我们可以一直跳\(v=r\)的fa,根据定义如果没有trans[v][c]我们要更新trans[v][S[r+1]]。然后一直跳如果直到1才停下来,说明之前\(S[(i \in[1,r])...r]\)都没出现过,那没事了。

但是如果到中间一个\(v\)而trans[v][c]=x,说明\(v\)代表的\(S[i...r+1]\)之前被表示出来过,按照parent tree的定义我们要更新enspos,

然后明天再更?

原文地址:https://www.cnblogs.com/winlere/p/12122139.html

时间: 2024-07-31 19:09:04

关于SAM和广义SAM的相关文章

CF452E Three strings【广义SAM】

传送门 也是广义 SAM 的板子题,建好广义 SAM,统计 \(epA,epB,epC\),然后对于区间 \(ans[len[fa[x]]+1],...,ans[len[x]]\) 加上 \(epA\times epB\times epC\) 就行了,当然这个用差分实现简单快捷. #include <bits/stdc++.h> using namespace std; typedef long long LL; const int N=3e5+10; const int mod=1e9+7;

【HDU 4436】 str2int (广义SAM)

str2int Problem Description In this problem, you are given several strings that contain only digits from '0' to '9', inclusive.An example is shown below.101123The set S of strings is consists of the N strings given in the input file, and all the poss

【BZOJ 3926】 [Zjoi2015]诸神眷顾的幻想乡 (广义SAM)

3926: [Zjoi2015]诸神眷顾的幻想乡 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 974  Solved: 573 Description 幽香是全幻想乡里最受人欢迎的萌妹子,这天,是幽香的2600岁生日,无数幽香的粉丝到了幽香家门前的太阳花田上来为幽香庆祝生日. 粉丝们非常热情,自发组织表演了一系列节目给幽香看.幽香当然也非常高兴啦. 这时幽香发现了一件非常有趣的事情,太阳花田有n块空地.在过去,幽香为了方便,在这n块空地之间修建

bzoj 2806: [Ctsc2012]Cheat【广义SAM+二分+dp+单调队列】

把模板串建一个广义SAM 然后在线查询,每次在SAM上预处理出一个a[i]表示i位置向前最多能匹配多长的模板串 二分答案L,dp判断,设f[i]为·~i有几个匹配,转移显然是f[i]=max{f[i-1],f[j]+i-j(i-a[i]<=j<=i-L)},根据性质,i-a[i]是单调的(或者直接看a[i]的预处理过程也能看出来),所以这个dp可以用单调队列优化转移,最后判断是否f[n]>=L*0.9 #include<iostream> #include<cstdio

luogu3346 诸神眷顾的幻想乡 (广义SAM)

首先,让每一个叶节点做一次树根的话,每个路径一定至少有一次会变成直上直下的 于是对于每个叶节点作为根产生的20个trie树,把它们建到同一个广义SAM里 建法是对每个trie dfs去建,last就是父亲的那个节点:每次做一个新trie时,last给成root 然后答案就是每个节点表示的长度和 1 #include<bits/stdc++.h> 2 #define pa pair<int,int> 3 #define CLR(a,x) memset(a,x,sizeof(a)) 4

喵星球上的点名——记一个用广义SAM根号维护多串的技巧

喵星球的上的点名 给定一个字符串集合S,每次给定T询问S中有多少个字符串中包含T,最后询问S中的每一个字符串包含了多少次给定的T. 思路 考虑将这S个字符串建立广义SAM,那么我们每次将T放到广义SAM中去匹配,最后匹配到的节点的parent子树中来自不同串的结束位置数就是第一问的答案. 同样我们每次匹配完之后在节点处打上标记,第二问S中每一个字符串的答案就是每一个结束位置能够一直往上跳链跳到的不同的节点的标记之和. 考虑如何实现上述过程,在广义SAM中,假设一个节点在SAM中的有效节点数量为\

bzoj5084 hashit 广义SAM+树链的并

题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=5084 题解 考虑平常对于静态问题,我们应该如何用 SAM 求本质不同的子串个数. 对于一个常规的 SAM,这个东西应该是 \(\sum\limits_{i\in V} len_i - len_{fa_i}\). 很容易发现,我们如果把这个字符串每一个时刻的前一个字符和后一个字符给连接起来,这是一个树的关系. 考虑对这个树建立一棵广义 SAM. 但是上面的结论在广义 SAM 中不适用.不适用的

[HAOI2016]找相同字符(广义SAM)

[HAOI2016]找相同字符(广义SAM) 题面 给定两个字符串,求出在两个字符串中各取出一个子串使得这两个子串相同的方案数.两个方案不同当且仅当这两个子串中有一个位置不同. 分析 此题有一个比较繁琐的后缀数组做法,但是用广义SAM可以秒杀. 把两个串建成广义SAM,对于每个后缀,记录\(endpos\)集合中落在第一个串中和第二个串中的位置个数,记为\(cnt_{x,0},cnt_{x,1}\). 对于自动机上的每个节点\(x\),出现位置方案数的贡献是\(cnt_{x,0} \cdot c

【bzoj3926- [Zjoi2015]诸神眷顾的幻想乡】广义sam

题意:给定一棵树,每个节点有一个颜色,问树上有多少种子串(定义子串为某两个点上的路径),保证叶子节点数<=20.n<=10^5 题解: 叶子节点小于等于20,考虑将每个叶子节点作为根把树给提起来形成一棵trie,然后定义这棵树的子串为从上到下的一个串(深度从浅到深). 这样做我们可以发现每个子串必定是某棵trie上的一段直线.统计20棵树的不同子串只需要把它们建到一个自动机上就行了,相当于把20棵trie合并成一棵大的.对于每个节点x,它贡献的子串数量是max[x]-min[x],又因为min