后缀数组小结

后缀数组是处理字符串问题的有力工具。

其中有些变量需要说明下,sa[i]是排名为第i的后缀所在字符串中的位置。height[i]表示sa[i-1]和sa[i]两个后缀的最长公共前缀,即相邻排名两串的公共前缀。

LCP(i,j)也就是后缀数组中第i个和第j个后缀的最长公共前缀的长度

例题,uva 12506,求区别所有字符串的最少字符数

具体见代码:

View Code
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<climits>
using namespace std;

#define maxn 1000009
int wa[maxn],wb[maxn],wv[maxn],wsm[maxn],sa[maxn],Len[maxn],pos[maxn];
int cmp(int *r,int a,int b,int l)
{return r[a]==r[b]&&r[a+l]==r[b+l];}
void da(int *r,int *sa,int n,int m)
{
    int i,j,p,*x=wa,*y=wb,*t;
    for(i=0;i<m;i++) wsm[i]=0;
    for(i=0;i<n;i++) wsm[x[i]=r[i]]++;
    for(i=1;i<m;i++) wsm[i]+=wsm[i-1];
    for(i=n-1;i>=0;i--) sa[--wsm[x[i]]]=i;
    for(j=1,p=1;p<n;j*=2,m=p)
    {
        for(p=0,i=n-j;i<n;i++) y[p++]=i;
        for(i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j;
        for(i=0;i<n;i++) wv[i]=x[y[i]];
        for(i=0;i<m;i++) wsm[i]=0;
        for(i=0;i<n;i++) wsm[wv[i]]++;
        for(i=1;i<m;i++) wsm[i]+=wsm[i-1];
        for(i=n-1;i>=0;i--) sa[--wsm[wv[i]]]=y[i];
        for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++)
            x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
    }
    return;
}
int Rank[maxn],height[maxn];
void calheight(int *r,int *sa,int n)
{
    int i,j,k=0;
    for(i=1;i<=n;i++) Rank[sa[i]]=i;
    for(i=0;i<n;height[Rank[i++]]=k)
        for(k?k--:0,j=sa[Rank[i]-1];r[i+k]==r[j+k];k++);
    return;
}
int RMQ[maxn];
int mm[maxn];
int best[20][maxn];
void initRMQ(int n)
{
    for(int i = 0; i <= n; i++)
        RMQ[i] = height[i];
    int i,j,a,b;
    for(mm[0]=-1,i=1;i<=n;i++)
        mm[i]=((i&(i-1))==0)?mm[i-1]+1:mm[i-1];
    for(i=1;i<=n;i++) best[0][i]=i;
    for(i=1;i<=mm[n];i++)
        for(j=1;j<=n+1-(1<<i);j++)
        {
            a=best[i-1][j];
            b=best[i-1][j+(1<<(i-1))];
            if(RMQ[a]<RMQ[b]) best[i][j]=a;
            else best[i][j]=b;
        }
    return;
}

int askRMQ(int a,int b)
{
    int t;
    t=mm[b-a+1];b-=(1<<t)-1;
    a=best[t][a];b=best[t][b];
    return RMQ[a]<RMQ[b]?a:b;
}
int lcp(int a,int b)
{
    int t;
    a=Rank[a];b=Rank[b];
    if(a>b) {t=a;a=b;b=t;}
    return height[askRMQ(a+1,b)];
}

char ss[maxn];
int ans[maxn];

int main(){
    int cas;
    scanf("%d",&cas);
    for(int tcase=1;tcase<=cas;tcase++){
        int n;
        scanf("%d",&n);
        int cnt = 0;
        for(int i=1;i<=n;i++){
            scanf("%s",ss);
            int len = strlen(ss);
            pos[i] = cnt;
            Len[i] = len;
            for(int j=0;j<len;j++){
                ans[cnt++] = ss[j]-'a'+500;
            }
        }
        ans[cnt]=0;
        da(ans,sa,cnt+1,1280);
        calheight(ans,sa,cnt);
        initRMQ(cnt);
        int was = 0;
        for(int i=1;i<=n;i++){
            int ans1 = 0;
            for(int j=1;j<=n;j++){
                if(i==j)
                    continue;
                ans1 = max(ans1,lcp(pos[i],pos[j]));
            }
            was += ans1+1;
        }
        printf("%d\n",was);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/gray035/p/3033242.html