SPOJ 694 Distinct Substrings/SPOJ 705 New Distinct Substrings(后缀数组)

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 <= 50000

Output

For each test case output one number saying the number of distinct substrings.

Example

Input:
2
CCCCC
ABABA

Output:
5
9

题目大意:给一个字符串,问这个字符串中不同的子串一共有多少个。

思路:构建后缀数组。如样例ABABA的5个后缀排序后分别为:

A

ABA

ABABA

BA

BABA

我们可以看作所有后缀的所有前缀构成所有的子串。

从上面可以看出,在A中,A第一次出现。在ABA中,AB和ABA第一次出现。在ABABA中,ABAB和ABABA第一次出现。

那么容易看出,对于一个suffix(sa[i]),其中有height[i]个子串是和前一个重复了的。其他都没有和前一个重复,而且他们都不会和之前所有的子串重复(因为如果前面有和suffix(sa[i])的前缀子串重复的次数比suffix(sa[i-1])要多的话,它应该在suffix(sa[i])和suffix(sa[i-1])之间,这显然不符合后缀数组的性质)

所以求出height[]数组后,总的子串数为n*(n+1)/2,那么答案就为n*(n+1)/2 - sum{height[]}

代码(705:0.75S)

 1 #include <cstdio>
 2 #include <algorithm>
 3 #include <cstring>
 4 #include <iostream>
 5 using namespace std;
 6 typedef long long LL;
 7 
 8 const int MAXN = 50010;
 9 
10 int sa[MAXN], c[MAXN], rank[MAXN], height[MAXN], tmp[MAXN];
11 char s[MAXN];
12 int T, n;
13 
14 void makesa(int m) {
15     memset(c, 0, m * sizeof(int));
16     for(int i = 0; i < n; ++i) ++c[rank[i] = s[i]];
17     for(int i = 1; i < m; ++i) c[i] += c[i - 1];
18     for(int i = 0; i < n; ++i) sa[--c[rank[i]]] = i;
19     for(int k = 1; k < n; k <<= 1) {
20         for(int i = 0; i < n; ++i) {
21             int j = sa[i] - k;
22             if(j < 0) j += n;
23             tmp[c[rank[j]]++] = j;
24         }
25         int j = c[0] = sa[tmp[0]] = 0;
26         for(int i = 1; i < n; ++i) {
27             if(rank[tmp[i]] != rank[tmp[i - 1]] || rank[tmp[i] + k] != rank[tmp[i - 1] + k])
28                 c[++j] = i;
29             sa[tmp[i]] = j;
30         }
31         memcpy(rank, sa, n * sizeof(int));
32         memcpy(sa, tmp, n * sizeof(int));
33     }
34 }
35 
36 void calheight() {
37     for(int i = 0, k = 0; i < n; height[rank[i++]] = k) {
38         if(k > 0) --k;
39         int j = sa[rank[i] - 1];
40         while(s[i + k] == s[j + k]) ++k;
41     }
42 }
43 
44 LL solve() {
45     LL ret = LL(n) * (n - 1) / 2;
46     for(int i = 1; i < n; ++i) ret -= height[i];
47     return ret;
48 }
49 
50 int main() {
51     scanf("%d", &T);
52     while(T--) {
53         scanf("%s", s);
54         n = strlen(s) + 1;
55         makesa(128);
56         calheight();
57         printf("%lld
", solve());
58     }
59 }
View Code
原文地址:https://www.cnblogs.com/oyking/p/3536353.html