-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDistinct Substrings SPOJ
More file actions
86 lines (73 loc) · 3.02 KB
/
Distinct Substrings SPOJ
File metadata and controls
86 lines (73 loc) · 3.02 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
import java.io.*;
import java.util.Arrays;
import java.util.Comparator;
/*
* Solved with suffix array.
* Observation: A substring of S is a prefix of some suffix of S.
* After sorting the suffix array sa, the number of distinct substrings contributed by the
* suffix s[sa[i],n-1] is n-sa[i]-lcp[i], where lcp[i] is the length of the longest common
* prefix between s[sa[i-1],n-1] and s[sa[i],n-1].
*/
public class Main {
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
PrintWriter out = new PrintWriter(new BufferedOutputStream(System.out));
public static void main(String[] args) throws IOException {
new Main().run();
}
void run() throws IOException {
int testcases = Integer.parseInt(in.readLine());
while (testcases-- > 0) {
solve();
}
out.flush();
}
void solve() throws IOException {
// Declared as final due the their usage in building a comparator
final char[] str = in.readLine().toCharArray();
final int n = str.length;
// Construct suffix array
// suffixArray[i] represents str.substring(suffixArray[i], n)
Integer[] suffixArray = new Integer[n]; // Integer instead of int for using Arrays.sort()
for (int i = 0; i < n; i++)
suffixArray[i] = i;
// Sort the suffix array by the suffixes
Arrays.sort(suffixArray, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
int i = o1, j = o2;
for(; i < n && j < n; i++, j++) {
if (str[i] != str[j])
return str[i] - str[j];
}
return j-i;
}
});
// Find the length of the longest common prefix for consecutive suffixes
int[] lcp = calculateLCP(str, suffixArray);
// The number of distinct substrings is the sum of the difference between the length of
// each suffix and its corresponding lcp with previous suffix. This is because all
// substrings that are prefixes of the lcp have been counted.
int sum = 0;
for (int i = 0; i < n; i++)
sum += (n-suffixArray[i]) - lcp[i];
//out.println(Arrays.toString(suffixArray));
//out.println(Arrays.toString(lcp));
out.println(sum);
}
/**
* Calculate the length of longest common prefix for consecutive suffixes
*
* @return an array containing the lengths of longest common prefix for the given suffix array.
*/
private int[] calculateLCP(char[] str, Integer[] suffixArray) {
int n = str.length;
int[] lcp = new int[n];
for (int i = 1; i < n; i++) {
// Calculate the length of the longest common prefix between (i-1)-th and i-th suffixes
int index1 = suffixArray[i-1], index2 = suffixArray[i];
while (index1 < n && index2 < n && str[index1++] == str[index2++])
lcp[i]++;
}
return lcp;
}
}