Given a string, we need to find the total number of its distinct substrings.
Input
T- number of test cases. T<=20;
Each test case consists of one string, whose length is <= 1000
Output
For each test case output one number saying the number of distinct substrings.
Example
Sample Input:
2
CCCCC
ABABA
Sample Output:
5
9
Explanation for the testcase with string ABABA:
len=1 : A,B
len=2 : AB,BA
len=3 : ABA,BAB
len=4 : ABAB,BABA
len=5 : ABABA
Thus, total number of distinct substrings is 9.
解法一、
所有的子串都可以通过某个后缀的前缀得到
那么这个问题就转化成了所有后缀中不相同的前缀一共有多少个
那么这个问题就转化成了所有后缀中不相同的前缀一共有多少个
先说一个后缀suffix(sa[i])可以产生n-sa[i]+1个前缀
但是有重复的,重复个数就是height[i]
所有不重复前缀是n-sa[i]+1-height[i]
但是有重复的,重复个数就是height[i]
所有不重复前缀是n-sa[i]+1-height[i]
注意第0号后缀是没法和第-1号后缀比较(因为第-1号后缀就不存在)
这样的话就会导致最后的答案少计算
这样的话就会导致最后的答案少计算
这里采用的方法就是给这个字符串后面加一个未出现过的字符
这个新长度的字符串求解
这个新长度的字符串求解
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #define F(x) ((x) / 3 + ((x) % 3 == 1 ? 0 : tb)) 5 #define G(x) ((x) < tb ? (x) * 3 + 1 : ((x) - tb) * 3 + 2) 6 using namespace std; 7 const int N = 1005; 8 int c[N],sa[N*3]; 9 int ranks[N*3], height[N*3],s[N]; 10 char str[N]; 11 bool pan(int *x,int i,int j,int k,int n) 12 { 13 int ti=i+k<n?x[i+k]:-1; 14 int tj=j+k<n?x[j+k]:-1; 15 return x[i]==x[j]&&ti==tj; 16 } 17 void build_SA(int n,int r) 18 { 19 int *x=ranks,*y=height; 20 for(int i=0; i<r; i++)c[i]=0; 21 for(int i=0; i<n; i++)c[s[i]]++; 22 for(int i=1; i<r; i++)c[i]+=c[i-1]; 23 for(int i=n-1; i>=0; i--)sa[--c[s[i]]]=i; 24 r=1; 25 x[sa[0]]=0; 26 for(int i=1; i<n; i++) 27 x[sa[i]]=s[sa[i]]==s[sa[i-1]]?r-1:r++; 28 for(int k=1; r<n; k<<=1) 29 { 30 int yn=0; 31 for(int i=n-k; i<n; i++)y[yn++]=i; 32 for(int i=0; i<n; i++) 33 if(sa[i]>=k)y[yn++]=sa[i]-k; 34 for(int i=0; i<r; i++)c[i]=0; 35 for(int i=0; i<n; i++)++c[x[y[i]]]; 36 for(int i=1; i<r; i++)c[i]+=c[i-1]; 37 for(int i=n-1; i>=0; i--)sa[--c[x[y[i]]]]=y[i]; 38 swap(x,y); 39 r=1; 40 x[sa[0]]=0; 41 for(int i=1; i<n; i++) 42 x[sa[i]]=pan(y,sa[i],sa[i-1],k,n)?r-1:r++; 43 } 44 for(int i=0; i<n; i++)ranks[i]=x[i]; 45 } 46 void get_height(int n) 47 { 48 int i,j,k=0; 49 for(i=1; i<=n; i++)ranks[sa[i]]=i; 50 for(i=0; i<n; i++) 51 { 52 if(k)k--; 53 else k=0; 54 j=sa[ranks[i]-1]; 55 while(s[i+k]==s[j+k])k++; 56 height[ranks[i]]=k; 57 } 58 } 59 int main() { 60 int t; 61 scanf("%d", &t); 62 while (t--) { 63 scanf("%s", str); 64 int len = strlen(str); 65 for (int i = 0; i < len; i++) 66 s[i] = (int)str[i]; 67 s[len] = 0; 68 build_SA(len+1,200); 69 get_height(len); 70 int res = 0; 71 for (int i = 1; i <= len; i++) 72 //printf("%d ",height[i]), 73 res += ((len-1) - sa[i]+1 - height[i]); 74 printf("%d ", res); 75 } 76 return 0; 77 }
解法二、
先请出来一共有多少子串,即(n+1)*n/2个,然后height数组的值就是相同前缀的数量,所以用总个数减去这个字符串的所有后缀
形成的height就是结果
形成的height就是结果
因为我的代码在原字符串基础上添加了一个字符,所以第0号后缀不是原字符串的,所以for循环从2到n
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #define F(x) ((x) / 3 + ((x) % 3 == 1 ? 0 : tb)) 5 #define G(x) ((x) < tb ? (x) * 3 + 1 : ((x) - tb) * 3 + 2) 6 using namespace std; 7 const int N = 1005; 8 int c[N],sa[N*3]; 9 int ranks[N*3], height[N*3],s[N]; 10 char str[N]; 11 bool pan(int *x,int i,int j,int k,int n) 12 { 13 int ti=i+k<n?x[i+k]:-1; 14 int tj=j+k<n?x[j+k]:-1; 15 return x[i]==x[j]&&ti==tj; 16 } 17 void build_SA(int n,int r) 18 { 19 int *x=ranks,*y=height; 20 for(int i=0; i<r; i++)c[i]=0; 21 for(int i=0; i<n; i++)c[s[i]]++; 22 for(int i=1; i<r; i++)c[i]+=c[i-1]; 23 for(int i=n-1; i>=0; i--)sa[--c[s[i]]]=i; 24 r=1; 25 x[sa[0]]=0; 26 for(int i=1; i<n; i++) 27 x[sa[i]]=s[sa[i]]==s[sa[i-1]]?r-1:r++; 28 for(int k=1; r<n; k<<=1) 29 { 30 int yn=0; 31 for(int i=n-k; i<n; i++)y[yn++]=i; 32 for(int i=0; i<n; i++) 33 if(sa[i]>=k)y[yn++]=sa[i]-k; 34 for(int i=0; i<r; i++)c[i]=0; 35 for(int i=0; i<n; i++)++c[x[y[i]]]; 36 for(int i=1; i<r; i++)c[i]+=c[i-1]; 37 for(int i=n-1; i>=0; i--)sa[--c[x[y[i]]]]=y[i]; 38 swap(x,y); 39 r=1; 40 x[sa[0]]=0; 41 for(int i=1; i<n; i++) 42 x[sa[i]]=pan(y,sa[i],sa[i-1],k,n)?r-1:r++; 43 } 44 for(int i=0; i<n; i++)ranks[i]=x[i]; 45 } 46 void get_height(int n) 47 { 48 int i,j,k=0; 49 for(i=1; i<=n; i++)ranks[sa[i]]=i; 50 for(i=0; i<n; i++) 51 { 52 if(k)k--; 53 else k=0; 54 j=sa[ranks[i]-1]; 55 while(s[i+k]==s[j+k])k++; 56 height[ranks[i]]=k; 57 } 58 } 59 int main() 60 { 61 int t; 62 scanf("%d", &t); 63 while (t--) 64 { 65 scanf("%s", str); 66 int len = strlen(str); 67 for (int i = 0; i < len; i++) 68 s[i] = (int)str[i]; 69 s[len] = 0; 70 build_SA(len+1,200); 71 get_height(len); 72 int res = ((len+1)*len)/2; 73 for (int i = 2; i <= len; i++) 74 //printf("%d ",height[i]), 75 res -= height[i]; 76 printf("%d ", res); 77 } 78 return 0; 79 }