[OI笔记]后缀自动机

本来没打算写的,不过想想看后缀自动机的理论看了两三天了才有点懂(我太傻了)…下周期末考的话大概要去复习一下文化课感觉回来又要忘得差不多,还是开篇blog记一下好了。

相关的资料:

cls当年的课件:2012年noi冬令营陈立杰讲稿

一篇不错的blog:http://www.cnblogs.com/meowww/p/6394960.html

因为博主比较懒(菜)所以这里就大概记一些关键的东西(其实也就只复述了一遍建SAM的过程,大概在cls课件40页左右的地方)。

用$p$表示$p=ST(T)$且$Right(p)=\{Lenght+1\}$的点(代码里用$last$记录),对于字符串$T$的SAM,我们在后面加入一个新的字符$x$,新建$np=ST(Tx),val[np]=val[p]+1$,对$p$所有没有$x$标号的祖先$v$,令$tr[v][x]=np$,也就是连向我们新加的点。

就这样找到第一个有$x$标号的祖先$v_p$,这里有几种情况。如果没有找到这样的$v_p$直接令$suf[np]=root$(根作为$np$的父亲),然后就可以结束了。否则令$q=tr[v_p][x]$,这时候如果$val[v_p]+1=val[q]$的话直接让$suf[np]=q$然后结束,但是如果不行的话就有点麻烦了,这时候我们要再建一个点$nq:tr[nq][*]=tr[q][*]$,然后$suf[nq]=suf[q],suf[q]=suf[np]=nq$,最后对所有$tr[v][x]==q$的祖先$v$都改成$tr[v][x]=nq$。

最后当然不要忘记更新$last$。

构造大概就是这样子啦。

inline int newNode(int x)
{
    val[++cnt]=x;return cnt;
}
inline void insert(int x)
{
    int p=last,np=newNode(val[p]+1);memset(tr[np],0,sizeof tr[np]);
    while(p&&!tr[p][x])tr[p][x]=np,p=suf[p];
    if(!p)suf[np]=1;
    else
    {
        int q=tr[p][x];
        if(val[q]==val[p]+1)suf[np]=q;
        else
        {
            int nq=newNode(val[p]+1);
            memcpy(tr[nq],tr[q],sizeof tr[nq]);
            suf[nq]=suf[q];suf[np]=suf[q]=nq;
            while(p&&tr[p][x]==q)tr[p][x]=nq,p=suf[p];
        }
    }
    last=np;
}

写起来还是挺短的

原文地址:https://www.cnblogs.com/yoooshinow/p/8372722.html

时间: 2024-08-29 08:04:26

[OI笔记]后缀自动机的相关文章

hdu 4622 Reincarnation(后缀数组|后缀自动机|KMP)

Reincarnation Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 131072/65536 K (Java/Others) Total Submission(s): 2138    Accepted Submission(s): 732 Problem Description Now you are back,and have a task to do: Given you a string s consist of lo

BZOJ 3277 串 (广义后缀自动机)

3277: 串 Time Limit: 10 Sec Memory Limit: 128 MB Submit: 309 Solved: 118 [Submit][Status][Discuss] Description 字符串是oi界常考的问题.现在给定你n个字符串,询问每个字符串有多少子串(不包括空串)是所有n个字符串中至少k个字符串的子串(注意包括本身). Input 第一行两个整数n,k. 接下来n行每行一个字符串. Output 输出一行n个整数,第i个整数表示第i个字符串的答案. Sa

后缀自动机/后缀树

只是笔记罢了,不要看 关于DAWG: 见紫书P390 把后缀自动机上所有节点都设为接受态就形成DAWG,可以接受一个字符串的所有子串. 一个子串的end-set是它在原串w中出现位置(从1开始编号)的右端点集合. 在DAWG中,end-set相同的子串属于同一个状态. 原因没原因,这应该算定义吧? 任意两个节点的end-set要么不相交,要么是包含关系. 原因:在DAWG上走一步,当前end-set的变化是将原end-set中各个元素+1(要去掉超出字符串长度的元素),然后拆分成1个或多个新en

后缀自动机小结

后缀自动机小结 太神仙了学不来 由于每次写SAM的题都感觉是一次升华,于是决定好好的捋一捋SAM的相关知识,也许下面的东西并不是很清楚(毕竟我还是有点迷糊),欢迎指正! 定义 先介绍自动机 自动机(有限状态自动机),它的功能就是识别一个字符串,对于一个自动机\(A\),若它能识别一个字符串\(str\),则\(A(str)=true\),否则\(A(str)=false\) 自动机有五个重要的组成部分: 字符集:\(alpha\) 状态集合:\(state\) 初始状态集合:\(init\)(如

hiho一下第128周 后缀自动机二·重复旋律5

#1445 : 后缀自动机二·重复旋律5 时间限制:10000ms 单点时限:2000ms 内存限制:512MB 描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一个音乐旋律被表示为一段数构成的数列. 现在小Hi想知道一部作品中出现了多少不同的旋律? 解题方法提示 输入 共一行,包含一个由小写字母构成的字符串.字符串长度不超过 1000000. 输出 一行一个整数,表示答案. 样例输入 aab 样例输出 5 解题方法提示 小Hi:本周的题目其实就是给定一个字符串S,要求出S的所有不同子串的数

后缀自动机总结

后缀自动机是一种确定性有限自动机(DFA),它可以且仅可以匹配一个给定串的任意后缀. 构造一个可以接受一个给定串的所有后缀的不确定性有限自动机(NFA)是很容易的,我们发现我们用通用的将NFA转换成对应DFA的算法转换出来的DFA的状态数都很小(O(n)级别的,远远达不到指数级别).于是,人们就开始研究这种特殊的NFA,并提出了在线增量算法,用O(n)的时间复杂度构造该NFA的DFA.在转换过程中,DFA中对应的NFA中的状态集合其实就是我们的right集合.——————以上在胡扯———————

BZOJ 2946 Poi2000 公共串 后缀自动机

题目大意:求n个串的最长公共子串 太久没写SAM了真是-- 将第一个串建成后缀自动机,用其它的串进去匹配 每个节点记录每个串在上面匹配的最大长度 那么这个节点对答案的贡献就是所有最大长度的最小值 对所有贡献取最大就行了= = 这最大最小看着真是别扭 #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define M 10100 using namesp

如何优雅的研究 RGSS3 番外(一) ruby 实现的后缀自动机

*我真的不会 ruby 呀* #encoding:utf-8 #============================================================================== # ■ Suffix_Automaton #------------------------------------------------------------------------------ # 后缀自动机. #============================

【BZOJ3926】[Zjoi2015]诸神眷顾的幻想乡 广义后缀自动机

[BZOJ3926][Zjoi2015]诸神眷顾的幻想乡 Description 幽香是全幻想乡里最受人欢迎的萌妹子,这天,是幽香的2600岁生日,无数幽香的粉丝到了幽香家门前的太阳花田上来为幽香庆祝生日. 粉丝们非常热情,自发组织表演了一系列节目给幽香看.幽香当然也非常高兴啦. 这时幽香发现了一件非常有趣的事情,太阳花田有n块空地.在过去,幽香为了方便,在这n块空地之间修建了n-1条边将它们连通起来.也就是说,这n块空地形成了一个树的结构. 有n个粉丝们来到了太阳花田上.为了表达对幽香生日的祝