SPOJ705 SUBST1 - New Distinct Substrings(后缀数组)
给一个字符串求有多少个不相同子串。
每一个子串一定都是某一个后缀的前缀。由此可以推断出总共有(1+n)*n/2个子串,那么下面的任务就是找这些子串中重复的子串。
在后缀数组中后缀都是排完序的,从sa[1]到sa[n],这么思考以某个串为前缀的子串有几个,那么容易想到重复子串的个数其实就是∑height[i]。
所以结果就是(1+n)*n/2-∑height[i]。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 #define INF (1<<30) 6 #define MAXN 55000 7 8 int wa[MAXN],wb[MAXN],wv[MAXN],ws[MAXN]; 9 int cmp(int *r,int a,int b,int l){ 10 return r[a]==r[b] && r[a+l]==r[b+l]; 11 } 12 int sa[MAXN],rank[MAXN],height[MAXN]; 13 void SA(int *r,int n,int m){ 14 int *x=wa,*y=wb; 15 16 for(int i=0; i<m; ++i) ws[i]=0; 17 for(int i=0; i<n; ++i) ++ws[x[i]=r[i]]; 18 for(int i=1; i<m; ++i) ws[i]+=ws[i-1]; 19 for(int i=n-1; i>=0; --i) sa[--ws[x[i]]]=i; 20 21 int p=1; 22 for(int j=1; p<n; j<<=1,m=p){ 23 p=0; 24 for(int i=n-j; i<n; ++i) y[p++]=i; 25 for(int i=0; i<n; ++i) if(sa[i]>=j) y[p++]=sa[i]-j; 26 for(int i=0; i<n; ++i) wv[i]=x[y[i]]; 27 for(int i=0; i<m; ++i) ws[i]=0; 28 for(int i=0; i<n; ++i) ++ws[wv[i]]; 29 for(int i=1; i<m; ++i) ws[i]+=ws[i-1]; 30 for(int i=n-1; i>=0; --i) sa[--ws[wv[i]]]=y[i]; 31 swap(x,y); x[sa[0]]=0; p=1; 32 for(int i=1; i<n; ++i) x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++; 33 } 34 35 for(int i=1; i<n; ++i) rank[sa[i]]=i; 36 int k=0; 37 for(int i=0; i<n-1; height[rank[i++]]=k){ 38 if(k) --k; 39 for(int j=sa[rank[i]-1]; r[i+k]==r[j+k]; ++k); 40 } 41 } 42 43 char str[MAXN]; 44 int r[MAXN],n; 45 int main(){ 46 int t; 47 scanf("%d",&t); 48 while(t--){ 49 scanf("%s",str); 50 n=0; 51 for(int i=0; str[i]; ++i){ 52 r[n++]=str[i]; 53 } 54 r[n]=0; 55 SA(r,n+1,128); 56 long long cnt=0; 57 for(int i=2; i<=n; ++i){ 58 cnt+=height[i]; 59 } 60 printf("%lld\n",(long long)(1+n)*n/2-cnt); 61 } 62 return 0; 63 }