广义SAM
参考
还有首先你要会SAM吧~
用途
相比与单串SAM,广义自动机能存储的是多个字符串。
有两种写法,第一种是离线利用trie树结构,第二种是在线伪广义SAM
离线+Trie
首先构建出trie树。
然后在trie树上BFS(),用\(pos[u]\)映射trie树上\(u\)节点对应SAM上的节点。
为什么不dfs,因为时间复杂度是trie树上所有叶子到根的距离和,证明BFS\(O(n)\)复杂度具体见上面参考博客。
code:
struct SAM {
int tr[N<<1][M],nd,len[N<<1],par[N<<1],pos[N*M];
queue<int> Q;
int Insert(int x,int lst) {
...略,返回新节点编号
}
void BFS() {
Q.push(1);pos[1]=1;
while(!Q.empty()) {
int u=Q.front(); Q.pop();
for(int i=0;i<26;i++) {
int v=T.go[u][i];
if(!v)continue;
pos[v]=Insert(i,pos[u]);
Q.push(v);
}
}
}S;
相信上面code的你能够很好的理解
在线
虽然它很伪,但通常跑的比上面那种快,而且对于很多问题在上面处理起来很方便。
方便讲解,先放一份原来插单串的code:
int Insert(int x,int lst) {
int p=lst,np=++nd;len[np]=len[p]+1;
for(;!tr[p][x];p=par[p])tr[p][x]=np;
if(!p) {par[np]=1;}
else {
int q=tr[p][x];
if(len[q]==len[p]+1) {par[np]=q;}
else {
int nq=++nd;par[nq]=par[q];len[nq]=len[p]+1;
for(int j=0;j<26;j++)tr[nq][j]=tr[q][j];
par[q]=par[np]=nq;
for(;tr[p][x]==q;p=par[p]) tr[p][x]=nq;
}
}
return np;
}
多串总体的区别就是每加入一个新串前让lst=1(root)
这样会出现之前插单串没出现过的情况:之前p=lst往上找tr[p][x]!=0之前肯定会存在tr[p][x]=0
然而现在可能一开始tr[lst][x]!=0,这有什么问题吗?就跟原来一样分两类讨论(拆点或不拆点)
问题就在于,这时新加的np是个空点,因为它是完全没有必要的。
令q=tr[lst][x]
- 如果len[q]=len[lst]+1,那此时直接返回q即可。
- 否则len[q]>len[lst]+1,还是要拆出nq,但是在(上面拆点)代码中唯一用到新点(np)的就是par[np]=nq
可len[nq]=len[np]的,nq已经包含了np了……
So Easy!直接不创np这个空点不就行了
我们上面也说明了现在新代码的写法。先判断tr[lst][x]!=0时就不定义新np点……最后return nq,否则写法跟上面单串一样的。 - code
struct SAM {
int tr[N<<1][M],nd,len[N<<1],par[N<<1];
queue<int> Q;
SAM() {nd=1;}
int Insert(int x,int lst) {
int p=lst;
if(tr[p][x]) {
int q=tr[p][x];
if(len[q]==len[p]+1)return q;
int nq=++nd;par[nq]=par[q];len[nq]=len[p]+1;
for(int j=0;j<c;j++)tr[nq][j]=tr[q][j];
for(;tr[p][x]==q;p=par[p]) tr[p][x]=nq;
return par[q]=nq;
}
int np=++nd;len[np]=len[p]+1;
for(;!tr[p][x];p=par[p])tr[p][x]=np;
if(!p) {par[np]=1;}
else {
int q=tr[p][x];
if(len[q]==len[p]+1) {par[np]=q;}
else {
int nq=++nd;par[nq]=par[q];len[nq]=len[p]+1;
for(int j=0;j<c;j++)tr[nq][j]=tr[q][j];
par[q]=par[np]=nq;
for(;tr[p][x]==q;p=par[p]) tr[p][x]=nq;
}
}
return np;
}
}S;
ps.最后强调一点:每个结点中的子串可能来自多个字符串。然而所有来源于相同字符串的子串endpos集合保证相同,而来源于不同字符串的endpos不一定相同.
很好理解(后面加一堆废话),假如加入了i-1个字符串(此时SAM满足上面性质)。第i个字符串的加入,会拆分原来的点(拆点不影响上面性质,只不过是对于同一个字符串同一个等价类被拆成多个节点罢了)。新加的i字符串肯定是满足的。
广义SAM的更多相关文章
- 【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上匹配. 设对于第\ ...
- BZOJ3926 ZJOI2015 诸神眷顾的幻想乡 Trie、广义SAM
传送门 树上的任意一条路径一定会在以某一个叶子节点为根的树上成为一条直上直下的链,而总共只有\(20\)个叶子节点. 于是每一次选所有叶子节点中的一个作为根,形成一个\(Trie\),把\(20\)个 ...
- hdu6405Make ZYB Happy 广义sam
题意:给出n(n<=10000)个字符串S[1~n],每个S[i]有权值val[i],随机等概率造一个由小写字母构成的字符串T,Sum = 所有含有子串T的S[i]的val[i]之积,求Sum的 ...
随机推荐
- Spring Boot配置文件加载顺序
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言 一.通过spring.config.location改变配置文件的位置 二.外部配置加载顺序 1.使用命令行参数指定加 ...
- 时间篇之centos6下修复的ntp操作(ntpd和ntpdate两个服务区别)
系统采样,本采样和命令都是在centos6.4的系统中进行 主要比较centos7和centos6之间的差异,因为大部分都开始采用centos7但是有些老系统还采用centos6,这样我们就需要熟悉c ...
- metasploit基本命令
一.核心命令 ? 帮助命令 banner 显示一个真棒metasploite横幅 cd 更改当前的工作目 color 切换颜色 connect 连接与主机通信 exit 退出控制台 get 获取特定于 ...
- 使用 Nginx 实现 URL 的重定向
1. 概述 老话说的好:取乎上,得其中:取乎中,得其下.因此我们不妨把目标定的高一些,去努力,才能得到更好回报. 言归正传,今天我们来聊聊 使用 Nginx 实现 URL 的重定向. 2. 使用 Ng ...
- JavaWeb学习day1-web入门&服务器安装
初步了解了web的发展历程,对比分析学习了动态页面与静态页面的优缺点. 选择安装使用最广泛的Tomcat 安装流程: 1.打开官网:https://tomcat.apache.org/ 2.选择下载版 ...
- jquery版本的ajax请求
首先引入 <script src="https://code.jquery.com/jquery-3.6.0.js"></script> $ 和 jqu ...
- 网络协议自动化逆向工具开山鼻祖discoverer 分析
本文系原创,转载请说明出处:信安科研人 也可关注微信公众号:信安科研人 原论文发表在2007年的USENIX上,链接如下:https://www.usenix.org/legacy/event/sec ...
- GET sql注入
靶机地址:192.168.43.156 攻击机地址:192.168.43.89 一.AppScan检查靶机sql漏洞 二.使用sqlmap利用SQL注入漏洞 1.sqlmap -u " ht ...
- HMS Core Discovery第14期直播预告~纵享丝滑剪辑,释放视频创作力
[导读] 拍摄.导入.特效.卡点.BGM-几步简单的操作,我们便可将生活的瞬间用视频记录与分享.应用前沿AI技术,提供一站式视频处理能力,帮助开发者们构建更智能.更易用.更专业的视频剪辑软件,打造视频 ...
- FileNotFoundError: [Errno 2] No such file or directory: 'image/1.jpg'问题解决
FileNotFoundError: [Errno 2] No such file or directory: 'image/1.jpg'问题 最近在学习爬虫,想爬一些图片并保存到本地,但是在下载图片 ...