后缀数组入门 SPOJ694

来源:互联网 发布:老馆艳后 知乎 编辑:程序博客网 时间:2024/06/06 08:28

后缀数组入门 SPOJ694


题目来源: http://www.spoj.com/problems/DISUBSTR/


题目大意

求单个子串的不重复字串的个数 (T<=20,len<=1000)

这是一道经典的后缀数组入门题。
由于刚开始学,对后缀数组的理解还很抽象,于是拿这道题先找找感觉。

首先,每个子串都可以理解成是某个后缀的前缀,这是联想到后缀数组算法的重要一步。

接着,对于每一个sa[i]后缀数组,含义为第i小的后缀的起始位置是sa[i],那么它最多能得到字串个数为:n-sa[i]。

对于每一个height[i]数组,即LCP(i-1,i),的含义为第i小的后缀与第i-1小的后缀的最长公共前缀。那么重复的子串个数为:height[i],实际产生的子串个数为:n-sa[i]-height[i]。

  • 一开始把height数组错误的理解成以i开始的后缀与以i-1开始的后缀的最长公共前缀,百思不得其解,后来回头重看了一遍,才发现后缀数组的神奇之处。orz

贴一发kuangbin大大的模板

void build_sa(int s[],int n,int m){    int i,j,p,*x=t1,*y=t2;    for(i=0;i<m;i++)c[i]=0;    for(i=0;i<n;i++)c[x[i]=s[i]]++;    for(i=1;i<m;i++)c[i]+=c[i-1];    for(i=n-1;i>=0;i--)sa[--c[x[i]]]=i;    for(j=1;j<=n;j<<=1){        p=0;        for(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<m;i++)c[i]=0;        for(i=0;i<n;i++)c[x[y[i]]]++;        for(i=1;i<m;i++)c[i]+=c[i-1];        for(i=n-1;i>=0;i--)sa[--c[x[y[i]]]]=y[i];        swap(x,y);        p=1;x[sa[0]]=0;        for(i=1;i<n;i++)            x[sa[i]]=y[sa[i-1]]==y[sa[i]] && y[sa[i-1]+j]==y[sa[i]+j]?p-1:p++;        if(p>=n)break;        m=p;    }}void getHeight(int s[],int n){    int i,j,k=0;    for(i=0;i<=n;i++)rank[sa[i]]=i;    for(i=0;i<n;i++){        if(k)k--;        j=sa[rank[i]-1];        while(s[i+k]==s[j+k])k++;        height[rank[i]]=k;    }}
0 0