-
Notifications
You must be signed in to change notification settings - Fork 0
/
MOU1H(nlog n suffix arr & lcp).cpp
135 lines (121 loc) · 2.85 KB
/
MOU1H(nlog n suffix arr & lcp).cpp
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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
#include <bits/stdc++.h>
#define MOD 1000000009
using namespace std;
typedef long long ll;
#define M 1000005
// O(n log n) - Manber and Myers
int a[M]; // input string or number
int rank[M], pos[M];
int cnt[M], next[M];
bool bh[M], b2h[M];
bool smaller_first_char(int x, int y)
{
return a[x] < a[y];
}
void suffixSort(int n)
{
for (int i = 0; i < n; ++i)
{
pos[i] = i;
}
sort(pos, pos + n, smaller_first_char);
for (int i = 0; i < n; ++i)
{
bh[i] = i == 0 || a[pos[i]] != a[pos[i - 1]];
b2h[i] = false;
}
for (int h = 1; h < n; h <<= 1)
{
int buckets = 0;
for (int i = 0, j; i < n; i = j)
{
j = i + 1;
while (j < n && !bh[j])
j++;
next[i] = j;
buckets++;
}
if (buckets == n)
break;
for (int i = 0; i < n; i = next[i])
{
cnt[i] = 0;
for (int j = i; j < next[i]; ++j)
rank[pos[j]] = i;
}
cnt[rank[n - h]]++;
b2h[rank[n - h]] = true;
for (int i = 0; i < n; i = next[i])
{
for (int j = i; j < next[i]; ++j)
{
int s = pos[j] - h;
if (s >= 0)
{
int head = rank[s];
rank[s] = head + cnt[head]++;
b2h[rank[s]] = true;
}
}
for (int j = i; j < next[i]; ++j)
{
int s = pos[j] - h;
if (s >= 0 && b2h[rank[s]])
{
for (int k = rank[s] + 1; !bh[k] && b2h[k]; k++)
b2h[k] = false;
}
}
}
for (int i = 0; i < n; ++i)
{
pos[rank[i]] = i;
bh[i] |= b2h[i];
}
}
for (int i = 0; i < n; ++i)
rank[pos[i]] = i;
}
// O(n) - lcp - "Arrays and Its Applications" by Toru Kasai, Gunho Lee
int lcp[M];
// lcp[i] = lcp of suffix pos[i] and suffix pos[i-1]
// lcp[0] = 0
void getlcp(int n)
{
for (int i = 0; i < n; ++i)
rank[pos[i]] = i;
lcp[0] = 0;
for (int i = 0, h = 0; i < n; ++i)
{
if (rank[i] > 0)
{
int j = pos[rank[i] - 1];
while (i + h < n && j + h < n && a[i + h] == a[j + h])
h++;
lcp[rank[i]] = h;
if (h > 0)
h--;
}
}
}
int main()
{
int Cases;
ll n , ans;
scanf("%d" , &Cases);
while(Cases--)
{
scanf("%lld" , &n);
for(int i = 0 ; i<n ; i++)
scanf("%d" , &a[i]);
n--;
for(int i = 0 ; i<n ; i++)
a[i] = a[i+1] - a[i];
ans = n*(n+1) / 2; // total substrings
suffixSort(n);
getlcp(n);
for(int i = 0 ; i<n ; i++)
ans -= lcp[i];
printf("%lld\n" , ans%MOD);
}
}