• 后缀数组小结


    前言

    五分钟应该学完的算法由于看错无数遍变量意义导致(......)

    简介

    利用后缀性质倍增合并实现"快速"排序

    做法

    考虑暴力:把每个后缀提出来然后快排,时间复杂度(O(n^2logn))
    从少到多考虑优化:
    (h~~~~a~~~~v~~~~a~~~~n~~~~a~~~~a~~~~a)
    (2~~~~1~~~~4~~~~1~~~~3~~~~1~~~~1~~~~1)
    (21,14,41,13,31,11,11,10)
    (6~~~~5~~~~8~~~~4~~~~7~~~~2~~~~2~~~~1)
    如果你对(st)表还熟悉的话能马上反应过来我们在干什么

    其实就是先得出以(s_i)开头的长度为(1)的排名,再用(s_{i-1})(s_i)的排名合并,得到所有长度为(2)的排名

    通过(logn)次倍增合并,最终得到所有后缀的排名

    My complete code

    还是来稍微解释一下变量意义吧:(y)第二关键字的排列,(x)第一关键字的排列的映射,(sa)当前伪后缀的排列

    在排序(y)的时候,([n-len+1,n])这些是没有第二关键字的(等同于第二关键字最优)

    ((sa[i]>len))(sa[i])里存的是位置,当位置(>len)时,是可以影响前半的字符串

    #include<bits/stdc++.h>
    using namespace std;
    typedef int LL;
    const LL maxn=1e6+9;
    LL n,m;
    LL c[maxn],x[maxn],y[maxn],sa[maxn];
    char s[maxn];
    inline void Get_sa(){
    	for(LL i=1;i<=n;++i) ++c[x[i]=s[i]];
    	for(LL i=2;i<=m;++i) c[i]+=c[i-1];
    	for(LL i=n;i>=1;--i) sa[c[x[i]]--]=i;
    	for(LL len=1;len<=n;len<<=1){
    		LL num(0);
    		for(LL i=n-len+1;i<=n;++i) y[++num]=i;
    		for(LL i=1;i<=n;++i) if(sa[i]>len) y[++num]=sa[i]-len;
    		for(LL i=1;i<=m;++i) c[i]=0;
    		for(LL i=1;i<=n;++i) ++c[x[i]];
    		for(LL i=2;i<=m;++i) c[i]+=c[i-1];
    		for(LL i=n;i>=1;--i) sa[c[x[y[i]]]--]=y[i],y[i]=0;
    		swap(x,y);
    		x[sa[1]]=num=1;
    		for(LL i=2;i<=n;++i)
    		    x[sa[i]]=(y[sa[i]]==y[sa[i-1]] && y[sa[i]+len]==y[sa[i-1]+len])?num:++num;
    		if(num==n) break;
    		m=num;
    	}
    }
    int main(){
    	scanf(" %s",s+1);
    	n=strlen(s+1); m=122;
    	Get_sa();
    	for(LL i=1;i<=n;++i) printf("%d ",sa[i]);
    	return 0;
    }
    

    常用

    (LCP(i,j))(sa[i])(sa[j])的最长公共前缀
    易证(LCP(i,j)=min{LCP(i,k),LCP(k,j)})
    那么我们仅需得到(height[i]=LCP(i,i-1))就能通过倍增求得所有的(LCP)

    (h[i]=height[rk[i]]),则(h[i]≥h[i-1]-1)
    证明:
    (~~~~~)设第(i-1)个字符在(sa)里的前驱为(k)
    (~~~~~1.)(k)(i-1)的首字符不同,则(h[i-1]=0),显然(h[i]≥h[i-1]-1)
    (~~~~~2.)(k)(i-1)的首字符相同,
    (~~~~~)(val=)(k+1)的后缀与(i)的后缀的最长公共前缀)=(height[rk[i-1]]-1)
    (~~~~~)显然相邻最优所以(LCP(i,i-1)≥val),所以(h[i]≥h[i-1]-1)

    至此我们可以实现(O(n))得到(height[i]),通过(O(nlogn))倍增预处理实现在线(O(logn))查询(LCP(i,j))

  • 相关阅读:
    编程心得5
    编程心得2
    心得2
    心得1
    7-11
    7-13
    7-9
    7-8
    7-12
    7-14
  • 原文地址:https://www.cnblogs.com/y2823774827y/p/10493129.html
Copyright © 2020-2023  润新知