关于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的任意一个子段。
可以发现一个确定的Trans[][]可以唯一确定一个串和SAM的形态。因为DAG的最长路是原串。
构建和复杂度证明
先说构建,构建的目的是要让这个东西能够识别新的后缀并且还要维持好Parent Tree的各种性质。
设原来是S[1...r]现在我们要变成S[1...r+1],S[r+1]=c:
首先可以发现的事情是,新状态一定包括\(S[1....r+1]\),设这个新状态为u,那么首先我们要让所有\(S[i...r+1]\)都被表示出来,我们可以一直跳\(v=r\)的fa,根据定义如果没有trans[v][c]我们要更新trans[v][c]。然后一直跳如果直到1才停下来,说明之前\(S[(i \in[1,r])...r]\)都没出现过,那没事了。
但是如果到中间一个\(v\)而trans[v][c]=x,说明\(v\)代表的\(S[i...r+1]\)之前被表示出来过,但按照parent tree的定义我们要更新endspos。此时有一个问题:
x代表的串最长的那个串可能不是我们当前要使得自动机以后识别的串S[i...r+1]。根据parent tree那个一条链的性质,这个集合一定要假如x的所有父亲的endpos集合中,但是可以发现,比S[i...r+1]小的串构成的endpos集合和大于等于S[i...r+1]的串endpos集合现在多了一个r+1,所以我们把x分裂成上下两半y和x',然后让x'和u共同当y的儿子。此时有一个问题是我们要更新一下trans,也就是把之前DAG图上到x的边全部转到y上,根据trans还有fa的性质这些边一定是v的连续一段fa,我们暴力修改一下(复杂度等下分析)。更新后的DAG只能只能识别原来的串+c这些串了(trans全更新了),并且我们成功更新了endpos。
分析一下复杂度:
首先如果trans[v][c]=NULL我们修改成r+1的这一部分复杂度是没问题的。因为你修改一次意味着一条DAG上的边,而DAG上的边是\(O(n)\)的。
唯一的问题是到了v之后,你还要跳连续的v的trans[v'][c]=x的一段链。这里复杂度是多少?
根据trans和Parent Tree分析一下,可以发现,任何一段暴力跳都可以对应上一个另一条树链上的一段,且另一段大小一定不小于这一段。那么一直这样对应下去一定可以找到一个最长的链。由于parent tree总点数是\(O(n)\)的,所以显然暴力跳的次数远远小于\(O(n)\) 。
广义SAM
普通SAM是针对一个串而言的,而广义SAM是针对一个trie树而言的。此时后缀和endpos的定义一一扩大,后缀变成了包括叶子的一段缀,endpos变成了trie树上的节点编号。
考虑一下对于一个串我们弄SAM出来利用的性质,我们只是利用了后缀的后缀也是后缀以及一个节点加上一个字符c后是不是仍然是后缀是确定的,在trie树上,叶子的缀的缀也是叶子的缀是显然的。现在SAM表达的含义是trie树上的节点,trans[u][c]表示的是在u这个点加上一个c字符后会到trie树上哪个点。
考虑以后我们之前的增量构造的含义,意义其实就是更新了到根的一条链的后缀,在这些后缀的后面加上一个字符。
一个构造方法是按照trie树bfs序构造。
关于SAM和广义SAM的更多相关文章
- 后缀自动机(SAM)+广义后缀自动机(GSA)
经过一顿操作之后竟然疑似没退役0 0 你是XCPC选手吗?我觉得我是! 稍微补一点之前丢给队友的知识吧,除了数论以外都可以看看,为Dhaka和新队伍做点准备... 不错的零基础教程见 IO WIKI ...
- 【HDU 4436】 str2int (广义SAM)
str2int Problem Description In this problem, you are given several strings that contain only digits ...
- 【BZOJ 3926】 [Zjoi2015]诸神眷顾的幻想乡 (广义SAM)
3926: [Zjoi2015]诸神眷顾的幻想乡 Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 974 Solved: 573 Descriptio ...
- 【BZOJ 3473】 字符串 (后缀数组+RMQ+二分 | 广义SAM)
3473: 字符串 Description 给定n个字符串,询问每个字符串有多少子串(不包括空串)是所有n个字符串中至少k个字符串的子串? Input 第一行两个整数n,k. 接下来n行每行一个字符串 ...
- luogu3346 诸神眷顾的幻想乡 (广义SAM)
首先,让每一个叶节点做一次树根的话,每个路径一定至少有一次会变成直上直下的 于是对于每个叶节点作为根产生的20个trie树,把它们建到同一个广义SAM里 建法是对每个trie dfs去建,last就是 ...
- loj#6031. 「雅礼集训 2017 Day1」字符串(SAM 广义SAM 数据分治)
题意 链接 Sol \(10^5\)次询问每次询问\(10^5\)个区间..这种题第一感觉就是根号/数据分治的模型. \(K\)是个定值这个很关键. 考虑\(K\)比较小的情况,可以直接暴力建SAM, ...
- Luogu P3181 [HAOI2016]找相同字符 广义$SAM$
题目链接 \(Click\) \(Here\) 设一个串\(s\)在\(A\)中出现\(cnt[s][1]\)次,在\(B\)中出现\(cnt[s][2]\)次,我们要求的就是: \[\sum cnt ...
- CF666E Forensic Examination 广义SAM、线段树合并、倍增、扫描线
传送门 朴素想法:对\(M\)个匹配串\(T_1,...,T_M\)建立广义SAM,对于每一次询问,找到这个SAM上\(S[pl...pr]\)对应的状态,然后计算出对于每一个\(i \in [l,r ...
- Luogu4022 CTSC2012 熟悉的文章 广义SAM、二分答案、单调队列
传送门 先将所有模板串扔进广义SAM.发现作文的\(L0\)具有单调性,即\(L0\)更小不会影响答案,所以二分答案. 假设当前二分的值为\(mid\),将当前的作文放到广义SAM上匹配. 设对于第\ ...
随机推荐
- Python类型模块:types
types模块中定义了Python中所有的类型,包括NoneType, TypeType, IntType, FloatType, BooleanType, BufferType, Bui ...
- Python深入:01内存管理
在Python中,一切都是指针. 一:对象三特性 所有的Python对象都有三个特性:身份,类型和值. 身份:每一个对象都有一个唯一的身份标识,任何对象 ...
- Nacos: Namespace 和 Endpoint 在生产环境下的最佳实践
随着使用 Nacos 的企业越来越多,遇到的最频繁的两个问题就是:如何在我的生产环境正确的来使用 namespace 以及 endpoint.这篇文章主要就是针对这两个问题来聊聊使用 nacos 过程 ...
- 「BZOJ2510」弱题
「BZOJ2510」弱题 这题的dp式子应该挺好写的,我是不会告诉你我开始写错了的,设f[i][j]为操作前i次,取到j小球的期望个数(第一维这么大显然不可做),那么 f[i][j]=f[i-1][j ...
- E. Remainder Problem 分块
两个操作 1对x位置的a[x]+y 2对所有i=y(mod x)求a[i]的和 我们肯定不能n^2 跑,稳超时,但是我们可以这样分块考虑. 为什么n^2不行?因为在x比较小的时候,这个求和操作次数太多 ...
- 在phpstudy中nginx伪静态配置
########################### #以下是虚拟主机配置 server { listen 80; server_name hzym.com; root "D:\phpst ...
- 3d爱心代码
<!doctype html> <html> <head> <meta charset="UTF-8"> <title> ...
- 微信小程序封装自定义弹窗
最近在做小程序的登录,需要同时获取用户手机号和头像昵称等信息,但是小程序又不支持单个接口同时获取两种数据,因此想到自定义一个弹窗,通过弹窗按钮触发获取手机号事件.记录一下. 具体代码如下: 业务代码中 ...
- Educational Codeforces Round 12 B C题、
B. Shopping 题意:n个顾客,每个顾客要买m个物品,商场总共有k个物品,看hint就只知道pos(x)怎么算了,对于每一个Aij在k个物品中找到Aij的位置.然后加上这个位置对于的数值,然后 ...
- 2019-10-5-dotnet-core-获取-MacAddress-地址方法
title author date CreateTime categories dotnet core 获取 MacAddress 地址方法 lindexi 2019-10-05 10:44:10 + ...