標籤:
題目描述:給定一個有小寫英文字母構成的字串T,求其不同子串個數
資料範圍及限制:一個串,長度不超過100000
輸入範例1:
ababa
輸出範例1:
9
輸入範例2
ebvylfeicorjhpovljmgqawckptcqfuynhvnqwokvowxjgvjhztxmgzwkgvuvhsilrslnzcvmconbabwrpfniknqsimyutwstzzc
輸出範例2:
4968
輸入範例3:
riokzisztaydqovqjcdnojfykqjfstevddxtxbtwgzlmwqnhijuemkxaaqmjqscdpnzgseezaexluxdmdkoijafpecganbycwsjs
輸出範例3:
4999757677
題解:
因為每個子串都是某個尾碼的首碼,所以想到用尾碼數組,首先要知道尾碼數組中height[i]的含義,height[i]不僅指排名第i的和排名第i-1的(尾碼)的最長相同首碼,還指排名第i的和排名1~i-1的最長相同首碼,可以舉幾個例子試試。
知道了這個性質,那麼每一個尾碼中只能由它得到的首碼的個數就是n-sa[i]-height[i],n-sa[i]得到這個尾碼的長度(我是從0開始的),height[i]個首碼在排名1~i-1的尾碼中已經得到,所以要減去,不計入答案。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 #include<algorithm> 6 #include<queue> 7 #include<vector> 8 using namespace std; 9 typedef long long LL;10 const LL maxn=200000;11 LL r[maxn],sa[maxn],wa[maxn],wb[maxn],wv[maxn],Ws[maxn];12 LL cmp(LL *r,LL a,LL b,LL l){13 return r[a]==r[b]&&r[a+l]==r[b+l];14 }15 void da(LL *r,LL *sa,LL n,LL m){16 LL i,j,p,*x=wa,*y=wb,*t;17 for(i=0;i<m;i++) Ws[i]=0;18 for(i=0;i<n;i++) Ws[x[i]=r[i]]++;19 for(i=1;i<m;i++) Ws[i]+=Ws[i-1];20 for(i=n-1;i>=0;i--) sa[--Ws[x[i]]]=i; 21 22 for(j=1,p=1;p<n;j*=2,m=p){23 for(p=0,i=n-j;i<n;i++) y[p++]=i;24 for(i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j;25 26 for(i=0;i<n;i++) wv[i]=x[y[i]]; 27 for(i=0;i<m;i++) Ws[i]=0;28 for(i=0;i<n;i++) Ws[wv[i]]++;29 for(i=0;i<m;i++) Ws[i]+=Ws[i-1];30 for(i=n-1;i>=0;i--) sa[--Ws[wv[i]]]=y[i];31 32 for(t=x,x=y,y=t,x[sa[0]]=0,p=1,i=1;i<n;i++)33 x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;34 }35 }36 LL rank[maxn],height[maxn];37 void calheight(LL *r,LL *sa,LL n){38 LL i,j,k=0;39 for(i=0;i<n;i++) rank[sa[i]]=i;40 for(i=0;i<n;height[rank[i++]]=k)41 for(k?k--:0,j=sa[rank[i]-1];r[i+k]==r[j+k];k++);42 return ;43 }44 char s[maxn];45 LL num[maxn],len,ans;46 int main(){47 freopen("distinct.in","r",stdin);48 freopen("distinct.out","w",stdout);49 scanf("%s",s); len=strlen(s);50 for(LL i=0;i<len;i++) num[i]=s[i]-‘a‘+2;51 da(num,sa,len,30);52 calheight(num,sa,len); height[0]=0;53 for(LL i=0;i<len;i++){54 LL k=len-sa[i];55 ans+=k-height[i];56 }57 printf("%lld",ans);58 return 0;59 }
不同子串