• 回文树总结


    回文树总结

    写马拉车还不如写回文树。
    ---BY 陈菊开

    回文树是啥

    原论文请转2017年集训队论文《回文树及其应用》BY翁文涛

    我感觉回文树/回文自动机相较于后缀自动机还是要好理解一点的(像我这种菜鸡到现在还不是很懂SAM)。
    回文树,顾名思义,就是要把一个串的所有回文子串丢到一棵树上。那要向SAM一样记录个什么鬼(endpos)啥的吗?不用。只需要对每一种本质不同的回文子串建一个节点就可以了。(“本质不同”指的是长度不同或是内容不同,与出现位置无关)

    对于一个节点,也就是一个回文子串,我们需要对他记录以下信息:

    (len):就是这个回文子串的长度
    (tr_c):在这个回文串的两边分别加上一个字符(c)后形成的回文串
    (fail):这个回文串的最长回文后缀

    为了方便表示回文树的结构,我们额外定义了两个根节点,(odd)(even)。其中(even)是一个长度为(0)的空串,(odd)是一个不存在的长度为(-1)的串。
    这样的定义可以让任何一个回文子串都存在(fail)。比如说,串(babbab)(fail)(bab),串(aba)(fail)(a),串(aa)(fail)(even),串(b)(fail)(odd)。特别的,定义(even)(fail)(odd)(odd)(fail)还是(odd)

    可以通过数学归纳法证明:一个串中本质不同的回文子串的个数是(O(n))级别的。

    考虑在原串(S)后面插入一个字符(c),这样就可能新形成若干以这个新字符(c)结尾的回文后缀。由于结束位置相同,所以较短的回文后缀也是较长的回文后缀的后缀。其中必然存在一个长度最长的回文后缀,所有其他的回文后缀都是他的后缀。
    那么这时候考虑一个回文串的基本性质:后缀等于前缀(长度相同的情况下)。
    所以既然所有其他回文后缀都是最长回文后缀的后缀,那么他们就也是这个最长回文后缀的前缀。
    既然是前缀,那么就说明他们在之前的位置已经出现过了。
    由此可以说明,在加入一个字符后,至多增加一个本质不同的回文子串。所以数量是(O(n))级别的。
    这样你已经知道了回文树/回文自动机的基本原理。但这还不够,因为你还得知道——

    怎么写

    这样写

    struct Palindromic_Tree{
    	int last,tot,tr[N][26],fa[N],len[N];
    	void init(){fa[0]=fa[1]=1;len[tot=1]=-1;}
    	void extend(int c,int n,char *s)
    		{
    			int v=last;
    			while (s[n-len[v]-1]!=s[n]) v=fa[v];
    			if (!tr[v][c])
    			{
    				int u=++tot,k=fa[v];
    				len[u]=len[v]+2;
    				while (s[n-len[k]-1]!=s[n]) k=fa[k];
    				fa[u]=tr[k][c];tr[v][c]=u;
    			}
    			last=tr[v][c];
    		}
    };
    

    其中(0)表示(even)(1)表示(odd)
    是不是特别好写?

    怎么用

    这个嘛。。。
    你可以求以某一个位置结尾的最长回文后缀的长度(就是(len_{last})
    你把后缀树建出来再维护一个(dep)就可以知道有多少个回文串(不同位置的算不同的)
    等等一些骚操作
    鉴于我题做的还不是很多所以以后再补(也可能是永远都不会补了)

  • 相关阅读:
    Spring bean
    spring bean初始化及销毁你必须要掌握的回调方法
    一张图搞懂Spring bean的完整生命周期
    获取Spring的ApplicationContext的几种方式
    你必须了解Spring的生态
    Spring的核心模块解析
    Spring 5.0
    纯分享scp协议如何工作
    我眼中的SAML (Security Assertion Markup Language)
    7z文件格式及其源码的分析(五)
  • 原文地址:https://www.cnblogs.com/zhoushuyu/p/8684479.html
Copyright © 2020-2023  润新知