Distinct Substrings SPOJ - DISUBSTR 后缀数组

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]
注意第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\n", res);
75     }
76     return 0;
77 }
 
解法二、
先请出来一共有多少子串,即(n+1)*n/2个,然后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\n", res);
77     }
78     return 0;
79 }
 

猜你喜欢

转载自www.cnblogs.com/kongbursi-2292702937/p/12322405.html