SPOJ705-New Distinct Substrings-后缀数组
计算所都不相同子串的个数,做法是所有子串的个数减去sigma(height[]).其中height数组的和便是所有相同子串的个数。
注意 N×(N+1)/2会爆int!但是最终答案在int内。所以使用sigma(n-sa[i]+1-height[i])的做法不会wa
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 5 using namespace std; 6 7 const int maxn = 5e4+10; 8 char line[maxn]; 9 int s[maxn]; 10 int sa[maxn],t1[maxn],t2[maxn],c[maxn]; 11 int rank[maxn],height[maxn]; 12 13 void build_sa(int s[],int n,int m) 14 { 15 int i,j,p,*x=t1,*y=t2; 16 //第一轮基数排序,如果s的最大值很大,可改为快速排序 17 for(i=0;i<m;i++)c[i]=0; 18 for(i=0;i<n;i++)c[x[i]=s[i]]++; 19 for(i=1;i<m;i++)c[i]+=c[i-1]; 20 for(i=n-1;i>=0;i--)sa[--c[x[i]]]=i; 21 for(j=1;j<=n;j<<=1) 22 { 23 p=0; 24 //直接利用sa数组排序第二关键字 25 for(i=n-j;i<n;i++)y[p++]=i;//后面的j个数第二关键字为空的最小 26 for(i=0;i<n;i++)if(sa[i]>=j)y[p++]=sa[i]-j; 27 //这样数组y保存的就是按照第二关键字排序的结果 28 //基数排序第一关键字 29 for(i=0;i<m;i++)c[i]=0; 30 for(i=0;i<n;i++)c[x[y[i]]]++; 31 for(i=1;i<m;i++)c[i]+=c[i-1]; 32 for(i=n-1;i>=0;i--)sa[--c[x[y[i]]]]=y[i]; 33 //根据sa和x数组计算新的x数组 34 swap(x,y); 35 p=1;x[sa[0]]=0; 36 for(i=1;i<n;i++) 37 x[sa[i]]=y[sa[i-1]]==y[sa[i]] && y[sa[i-1]+j]==y[sa[i]+j]?p-1:p++; 38 if(p>=n)break; 39 m=p;//下次基数排序的最大值 40 } 41 } 42 void getHeight(int s[],int n) 43 { 44 int i,j,k=0; 45 for(i=0;i<=n;i++)rank[sa[i]]=i; 46 for(i=0;i<n;i++) 47 { 48 if(k)k--; 49 j=sa[rank[i]-1]; 50 while(s[i+k]==s[j+k])k++; 51 height[rank[i]]=k; 52 } 53 } 54 55 int T; 56 57 int main() 58 { 59 scanf("%d",&T); 60 while(T--) 61 { 62 scanf("%s",line); 63 int N = strlen(line); 64 for(int i=0;i<=N;i++) 65 s[i] = line[i]; 66 67 build_sa(s,N+1,300); 68 getHeight(s,N); 69 70 long long len = N; 71 long long ans = len*(len+1)/2; 72 73 for(int i=2;i<=N;i++) 74 { 75 ans -= height[i]; 76 } 77 printf("%d\n",ans); 78 } 79 }