不同子串
题目描述:给定一个有小写英文字母构成的字符串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 }