• 【更新中】后缀数组学习笔记


    基于基数排序的倍增实现后缀数组

    后缀树组的基本做法是倍增,时间复杂度是O(nlogn),代码简短,思想巧妙。最妙的东西是基数排序,以及倍增字符串的比较单位字符串长度翻倍。
    当字符集很大的时候(1e9),后缀树组照样运行,而后缀自动机就很难搞,建边需要哈希。
    c++11的比较函数:sort(p, p+n, [&](const int &a, const int &b));

    int n, alpha=256, bkt[maxn], rk[maxn], sa[maxn], SA[maxn], RK[maxn];
    char s[maxn];
    int main(){
        scanf("%s", s+1); n=strlen(s+1);
        for(int i=1;i<=n;++i) bkt[s[i]]++;
        for(int i=1;i<=alpha;++i) bkt[i]+=bkt[i-1];
        for(int i=1;i<=n;++i) sa[bkt[s[i]]--]=i;
        for(int i=1;i<=n;++i) rk[sa[i]]=rk[sa[i-1]]+(s[sa[i-1]]!=s[sa[i]]);
        for(int p=1;p<=n;p<<=1){
            for(int i=1;i<=n;++i) bkt[sa[i]]=i;
            for(int i=n;i>=1;--i) if(sa[i]>p) SA[bkt[rk[sa[i]-p]]--]=sa[i]-p;
            for(int i=n;i>n-p;--i) SA[bkt[rk[i]]--]=i;
            #define cmp(x,y,p)  (rk[x]!=rk[y]||rk[x+p]!=rk[y+p])
            for(int i=1;i<=n;++i) RK[SA[i]]=RK[SA[i-1]]+cmp(SA[i],SA[i-1],p);
            for(int i=1;i<=n;++i) rk[i]=RK[i], sa[i]=SA[i];
            if(rk[sa[n]]>=n) break;
        }
    }
    

    有关lcp

    令 lcp(i,j) 表示排名为 i 和排名为 j 的后缀的最长公共前缀的长度。即 sa[i] 和 sa[j] 的最长公共前缀的长度。
    那么有:
    定理一:(lcp(l,r)=min(lcp(l,i),lcp(i,r))),其中 i 是 [l,r] 中任意一个数。
    定理二:(lcp(l,r)=min_{i=l+1}^{r}(lcp(i-1,i)))

    有关height数组和h数组

    height[i]表示排名为i的后缀与排名为i+1的后缀的lcp。
    h[i]=height[rnk[i]],表示下标为i的后缀与这个后缀排名下一个的后缀的lcp。
    h[sa[i]]=height[i],表示排名为i的后缀与排名为i+1的后缀的lcp。
    考虑根据后缀数组线性求h[i]。有:

    (h[rnk[i]] leq h[rnk[i]+1]]+1)

    后缀数组的好兄弟——调和级数

    待更

    练习1:求本质不同的子串

    总的子串个数减去重复的子串个数,(n*(n-1)/2-sum_i h[i])

    练习2:CF1073G Yet Another LCP Problem

    虚树,单调栈

    练习3:区间本质不同的子串

    是SAM和LCT的板子题

    练习4:

    定义区间匹配:区间长度一样;区间不交;$ h_l_{1 + i} + h_l_{2 + i} = h_l_1 + h_l_2 $。
    给定区间,询问源字符串里有多少区间与之匹配

    $ h_l_{1+i}-h_l_1 = h_l_2 - h_l_{2+i} $ 只和相对大小有关,故差分之。

    $ h_i^'=h_{i+1}-h_i $ ,匹配即相反数。

    根号平衡

    虽然左右端点的变动是nlogn,但是询问只有n。
    使得修改为O(1),查询复杂度为O(n)。
    每个块内开桶维护全局复杂度。询问的零散点暴力O(n)块内查询。

  • 相关阅读:
    OpenGL编程 基础篇(七)对象的变换——用实心体绘制3D场景
    mysql在查询结果列表前添加一列递增的序号列(最简)
    将中文字符串分割为数组 解决str_split中文乱码php
    file_get_contents 抓取网页乱码。
    js下的sleep实现
    js获取当前时间(昨天、今天、明天)
    JPA为字段设置默认值
    js实现点击按钮弹出上传文件的窗口
    Bootstrap使用模态框modal实现表单提交弹出框
    springboot使用Freemarker继承
  • 原文地址:https://www.cnblogs.com/ZhengkunJia/p/15496151.html
Copyright © 2020-2023  润新知