zoukankan      html  css  js  c++  java
  • SAM(后缀自动机)总结

    “写sam是肯定会去写的,这样才学的了字符串,后缀数组又不会用 >ω<,

    sam套上数据结构的感觉就像回家一样!

    里面又能剖分又能线段树合并,调试又好调,我爱死这种写法了 !qwq”

    SAM是一个DFA,它存储了某字符串的所有子串信息。

    待更。

    博主水平不行,尽量在退役前多更些。

    插入字符:

     1 void extend(int id,int&now)
     2 {
     3     int p=now;
     4     if(ch[p][id] && len[ch[p][id]]==len[p]+1)
     5     {
     6         now=ch[p][id];
     7         return;
     8     }
     9     int np=++tot;
    10     len[np]=len[p]+1;
    11     while(p && !ch[p][id])
    12     {
    13         ch[p][id]=np;
    14         p=fa[p];
    15     }
    16     if(!p)
    17     {
    18         fa[np]=1;
    19     }
    20     else
    21     {
    22         int q=ch[p][id];
    23         if(len[q]==len[p]+1)
    24         {
    25             fa[np]=q;
    26         }
    27         else
    28         {
    29             int nq=++tot;
    30             len[nq]=len[p]+1;
    31             fa[nq]=fa[q];
    32             for(int i=0;i<26;i++)
    33                 ch[nq][i]=ch[q][i];
    34             fa[q]=fa[np]=nq;
    35             while(p && ch[p][id]==q)
    36             {
    37                 ch[p][id]=nq;
    38                 p=fa[p];
    39             }
    40         }
    41     }
    42     now=np;
    43 }

    套路:

    每条路径与子串一一对应。

    $len_i$:该节点最长串的长度

    $Parent Tree$上的子树和:串的出现次数

    $len_i - len_{fa_i}$:该节点代表的串的数目

    部分题目选:

    (1)[SAM入门题][NOI2018]你的名字

    题目链接

    线段树合并维护$right$集合

    (2)[SAM入门题][CTSC2012]熟悉的文章

    题目链接

    $SAM$只是用来预处理的,求答案还要靠二分+单队$DP$

    (3)[SAM入门题][bzoj2555]Substring

    题目链接

    $LCT$对$Parent Tree$结构的维护

    (4)[bzoj3277]字符串

    题目链接

    广义后缀自动机的应用

    暴力搞复杂度大概是根号的,不会证明。

    (5)[bzoj5084]HASHIT

    题目链接

    带撤销后缀自动机,随机数据随便艹。

    upd:BFS建树形后缀树以后再进行DFS+树链求并统计答案就行了。

    (6)[USACO]牛奶模式

    题目链接

    后缀自动机的基本原理与使用

    (7)[洛谷元旦赛]WD与数列

    题目链接

    维护$right$集合的好题(似乎还要在parent树上跑启发式合并计算贡献,我并不会)

    现在可能会了。

    (8)[FZOJ2258]封印

    校内题目,没连接

    大概就是你知道$Parent$树是干啥的,形态如何,就能直接切掉。

    (9)[TJOI2016]字符串

    考虑求出 sam 上一个串 p 在 [l,r] 里出现的次数,这个可以通过数一数 p 的 right 集合里有多少在 $[l+len_p-1,r]$ 中出现。

    lcp 可以二分,倍增可以从区间 locate 子串,那么这个题就 $O(nlog^2 n)$ 了。

    upd:话说为啥没见过把状态设在sam节点上的DP题?

    upd:CF700E,已经单独更新

    (10)[十二省联考]字符串问题

    题目意思大概是描述给你一个连边关系,求 DAG 上最长路。

    直接暴力构图可以 $n^2$ ,用 hash 判断。

    如果考虑建后缀树,那么在一个节点上有短->长的后缀关系,另外父子关系也是后缀关系,拆点据此连边即可。

    只需要实现对区间 locate 子串即可,时间复杂度 $O(nlog n)$。

  • 相关阅读:
    25个PHP游戏编程脚本代码(转)
    [AJAXJSP]使用DWR框架验证用户名是否存在
    [AJAXJSP]验证用户名存在
    [Java基础]多线程求和小例子
    [JAVA算法]求子数组的最大和
    [JQury] slideToggle闪烁问题及解决办法
    [JAVA算法]递归求Fibbonicc序列方法
    Easy ui Datagrid(下拉、复选、只输入数字、文本) 追加、删除、更改
    Easy ui DataGrid 添加复选框 与 下拉
    Easy ui DataGrid 列文字多串行问题解决方案
  • 原文地址:https://www.cnblogs.com/bestwyj/p/10152256.html
Copyright © 2011-2022 走看看