后缀排序学习笔记

建议参考:后缀数组——处理字符串的有力工具
后缀排序即对一个字符串的每一个后缀进行排序,如果暴力进行排序,考虑到字符串比较的复杂度,效率至少是 O(n2) O ( n 2 ) 级别的.
考虑依次对每个位置开始的 2i 2 i 个字符进行分组,把他们看成一个字符串,从小到大枚举 i i 进行处理,sj,j+2i1的排名即 (sj,j+2i11+sj+2i1,j+2i1) ( s j , j + 2 i − 1 − 1 + s j + 2 i − 1 , j + 2 i − 1 ) 的排名,使用基数排序即可做到 O(nlog2n) O ( n l o g 2 n ) 的复杂度.
sa[i] s a [ i ] 表示第 i i 大的后缀的位置

bool cmp(LL *x,LL a,LL b,LL l)
{
    return x[a]==x[b] && x[a+l]==x[b+l];
}
void px()
{
    LL i,j,p,*x=X,*y=Y;
    fo(i,0,n-1) buc[x[i]=s[i]]++;
    fo(i,1,M) buc[i]+=buc[i-1];
    fd(i,n-1,0) sa[--buc[s[i]]]=i;//从大到小枚举
    for(j=1,p=0;p<n;j<<=1)
    {
        p=0;//别忘了
        fo(i,n-j,n-1) y[p++]=i;
        fo(i,0,n-1) if (sa[i]>=j) y[p++]=sa[i]-j;
        fo(i,0,n-1) _rk[i]=x[y[i]];
        qk(buc);
        fo(i,0,n-1) buc[_rk[i]]++;
        fo(i,1,M) buc[i]+=buc[i-1];
        fd(i,n-1,0) sa[--buc[_rk[i]]]=y[i];//从大到小枚举
        swap(x,y); p=1; x[sa[0]]=0; y[n]=-1;//别忘了
        fo(i,1,n-1)
        x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
    }
}

h[i]表示第 i i 大的后缀和第i1大的后缀的最长公共前缀,那么有 h[rk[i+1]]>=h[rk[i]] h [ r k [ i + 1 ] ] >= h [ r k [ i ] ] ,可以这样求

    fo(i,0,n-1) rk[sa[i]]=i;
    LL j=0;
    fo(i,0,n-1)
    {
        if (!rk[i]) continue;
        j=j?j-1:j;
        fo(j,j,n-1)
        if (s[i+j]!=s[sa[rk[i]-1]+j]) break;
        h[rk[i]]=j;
    }

SPOJ_NSUBSTR
题意:求长度为 1 1 n的重复次数最多子串的重复次数(可以相交)
先后缀排序求出 h h 数组,用单调栈左右各扫一遍求出每个位置i是哪一段极长区间的最小值,区间长度就是 ans[i] a n s [ i ] 的值

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值