SPOJ 694/705 后缀数组
题意:
求单个子串的不重复子串个数
题解:
一个字符串中的所有子串都必然是它的后缀的前缀。
对于每一个sa[i]后缀,它的起始位置sa[i],那么它最多能得到该后缀长度个子串(n-sa[i]个),而其中有height[i]个是与前一个后缀相同的,所以它能产生的实际后缀个数便是n-sa[i]-height[i]。遍历一次所有的后缀,将它产生的后缀数加起来便是答案。
View Code
1 #include <iostream> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cstdio> 5 #include <algorithm> 6 7 #define N 50050 8 9 using namespace std; 10 11 int wa[N],wb[N],wc[N],wv[N]; 12 int r[N],sa[N]; 13 char str[N]; 14 int rank[N],height[N]; 15 16 inline bool cmp(int *r,int a,int b,int l) 17 { 18 return r[a]==r[b]&&r[a+l]==r[b+l]; 19 } 20 21 inline void da(int *r,int *sa,int n,int m) 22 { 23 int i,j,p,*x=wa,*y=wb,*t; 24 for(i=0;i<m;i++) wc[i]=0; 25 for(i=0;i<n;i++) wc[x[i]=r[i]]++; 26 for(i=1;i<m;i++) wc[i]+=wc[i-1]; 27 for(i=n-1;i>=0;i--) sa[--wc[x[i]]]=i; 28 for(j=1,p=1;p<n;j<<=1,m=p) 29 { 30 for(i=n-j,p=0;i<n;i++) y[p++]=i; 31 for(i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j; 32 for(i=0;i<n;i++) wv[i]=x[y[i]]; 33 for(i=0;i<m;i++) wc[i]=0; 34 for(i=0;i<n;i++) wc[wv[i]]++; 35 for(i=1;i<m;i++) wc[i]+=wc[i-1]; 36 for(i=n-1;i>=0;i--) sa[--wc[wv[i]]]=y[i]; 37 for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++) 38 x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++; 39 } 40 } 41 42 inline void getheight(int *r,int *sa,int n) 43 { 44 int i,j,k=0; 45 for(i=1;i<=n;i++) rank[sa[i]]=i; 46 for(i=0;i<n;height[rank[i++]]=k) 47 for(k?k--:0,j=sa[rank[i]-1];r[i+k]==r[j+k];k++); 48 } 49 50 inline void go() 51 { 52 int n,ans=0; 53 scanf("%s",str); 54 n=strlen(str); 55 for(int i=0;i<n;i++) r[i]=str[i]; 56 r[n]=0; 57 da(r,sa,n+1,256); 58 getheight(r,sa,n); 59 for(int i=1;i<=n;i++) ans+=n-sa[i]-height[i]; 60 printf("%d\n",ans); 61 } 62 63 int main() 64 { 65 int cas;scanf("%d",&cas); 66 while(cas--) go(); 67 return 0; 68 }
没有人能阻止我前进的步伐,除了我自己!