后缀排序学习笔记

﹥>﹥吖頭↗ 提交于 2019-11-30 01:38:15

建议参考:后缀数组——处理字符串的有力工具
后缀排序即对一个字符串的每一个后缀进行排序,如果暴力进行排序,考虑到字符串比较的复杂度,效率至少是O(n2)级别的.
考虑依次对每个位置开始的2i个字符进行分组,把他们看成一个字符串,从小到大枚举i进行处理,sj,j+2i1的排名即(sj,j+2i11+sj+2i1,j+2i1)的排名,使用基数排序即可做到O(nlog2n)的复杂度.
sa[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大的后缀和第i1大的后缀的最长公共前缀,那么有h[rk[i+1]]>=h[rk[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
题意:求长度为1n的重复次数最多子串的重复次数(可以相交)
先后缀排序求出h数组,用单调栈左右各扫一遍求出每个位置i是哪一段极长区间的最小值,区间长度就是ans[i]的值

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!