题目:http://cojs.tk/cogs/problem/problem.php?pid=1709
1709. [SPOJ705]不同的子串
★★ 输入文件:subst1.in
输出文件:subst1.out
简单对比
时间限制:1 s 内存限制:256 MB
【题目描述】
给定一个字符串,计算其不同的子串个数。
【输入格式】
一行一个仅包含大写字母的字符串,长度<=50000
【输出格式】
一行一个正整数,即不同的子串个数。
【样例输入】
ABABA
【样例输出】
9
【来源】
SPOJ 705 New Distinct Substrings
自动选择评测机 打开 O2 优化COGS Grader无优化开关
提交代码 Pascal C C++
题解:
后缀数组
我们可以想到ans=总共子串的个数-相同的个数。
相同的个数即为height[]之和。
(len为字符串长度)总共子串的个数:
长度为1的个数:len
长度为2的个数:len-1
.
.
.
所以总共个数为len+(len-1)……+2+1=(len*(len-1))/2
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define MAXN 50010 4 #define LL long long 5 int Ws[MAXN],sa[MAXN],wa[MAXN],wb[MAXN],wv[MAXN],Rank[MAXN],height[MAXN]; 6 char str[MAXN]; 7 int cmp(int *r,int a,int b,int l){return (r[a]==r[b])&&(r[a+l]==r[b+l]);} 8 void DA(char *r,int *sa,int n,int m) 9 { 10 int i,j,p,*x=wa,*y=wb,*t; 11 for(i=0;i<m;i++)Ws[i]=0; 12 for(i=0;i<n;i++)Ws[x[i]=r[i]]++; 13 for(i=0;i<m;i++)Ws[i]+=Ws[i-1]; 14 for(i=n-1;i>=0;i--)sa[--Ws[x[i]]]=i; 15 for(j=1,p=1;p<n;j*=2,m=p) 16 { 17 for(p=0,i=n-j;i<n;i++)y[p++]=i; 18 for(i=0;i<n;i++)if(sa[i]>=j)y[p++]=sa[i]-j; 19 for(i=0;i<n;i++)wv[i]=x[y[i]]; 20 for(i=0;i<m;i++)Ws[i]=0; 21 for(i=0;i<n;i++)Ws[wv[i]]++; 22 for(i=0;i<m;i++)Ws[i]+=Ws[i-1]; 23 for(i=n-1;i>=0;i--)sa[--Ws[wv[i]]]=y[i]; 24 for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++) 25 x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++; 26 } 27 } 28 void calheight(int n) 29 { 30 int i,j,k=0; 31 for(i=1;i<=n;i++)Rank[sa[i]]=i; 32 for(i=0;i<n;height[Rank[i++]]=k) 33 for(k?k--:0,j=sa[Rank[i]-1];str[i+k]==str[j+k];k++); 34 } 35 int main() 36 { 37 freopen("subst1.in","r",stdin); 38 freopen("subst1.out","w",stdout); 39 int lstr,i; 40 LL ans=0; 41 scanf("%s",str); 42 lstr=strlen(str); 43 str[lstr+1]=0; 44 DA(str,sa,lstr+1,256); 45 calheight(lstr); 46 ans=((LL)(lstr+1)*lstr)/2; 47 for(i=2;i<=lstr;i++)ans-=(LL)height[i]; 48 printf("%lld",ans); 49 fclose(stdin); 50 fclose(stdout); 51 return 0; 52 }