Blog of RuSun

\begin {array}{c} \mathfrak {One Problem Is Difficult} \\\\ \mathfrak {Because You Don't Know} \\\\ \mathfrak {Why It Is Diffucult} \end {array}

P2408 不同子串个数

P2408 不同子串个数

$ht_i$ 表示后缀 $i$ 与其排名前面的后缀的最长公共前缀的长度。可以知道,所有子串都是一个后缀的前缀,所以 $ht_i$ 可以贡献长度为 $1\ldots ht _ i$ 的 $ht _ i$ 种前缀。我们希望找到一个和其他后缀的最长公共前缀,显然应该是 $ht_i$ ,如果存在一个串,它的最长公共前缀更长,那么它应该排名在该后缀的前一个。

aabaa ,后缀为 a aa baa abaa aabaa ,排序后为 a aa aabaa abaa baa 。贡献为 a aa a

查看代码
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
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 2e5 + 10;
char s[N];
int sa[N], rnk[N], ht[N], x[N], y[N], n, m, c[N];
void SA()
{
for (int i = 1; i <= n; i++)
c[x[i] = s[i]]++;
for (int i = 1; i <= m; i++)
c[i] += c[i - 1];
for (int i = n; i; i--)
sa[c[x[i]]--] = i;
for (int k = 1; k <= n; k <<= 1)
{
int cnt = 0;
for (int i = n - k + 1; i <= n; i++)
y[++cnt] = i;
for (int i = 1; i <= n; i++)
if (sa[i] > k)
y[++cnt] = sa[i] - k;
for (int i = 1; i <= m; i++)
c[i] = 0;
for (int i = 1; i <= n; i++)
c[x[i]]++;
for (int i = 2; i <= m; i++)
c[i] += c[i - 1];
for (int i = n; i; i--)
sa[c[x[y[i]]]--] = y[i];
for (int i = 1; i <= n; i++)
y[i] = x[i];
for (int i = 1; i <= n; i++)
x[i] = 0;
x[sa[1]] = 1;
cnt = 1;
for (int i = 2; i <= n; i++)
if (y[sa[i]] == y[sa[i - 1]] && y[sa[i] + k] == y[sa[i - 1] + k])
x[sa[i]] = cnt;
else
x[sa[i]] = ++cnt;
if (cnt == n)
return;
m = cnt;
}
}
void Height()
{
for (int i = 1; i <= n; i++)
rnk[sa[i]] = i;
for (int i = 1; i <= n; i++)
{
if (rnk[i] == 1)
continue;
int j = sa[rnk[i] - 1], k = max(0, ht[rnk[i - 1]] - 1);
while (i + k <= n && j + k <= n && s[i + k] == s[j + k])
k++;
ht[rnk[i]] = k;
}
}
int main()
{
scanf("%d%s", &n, s + 1);
for (int i = 1; i <= n; i++)
s[i] = s[i] - 'a' + 1;
m = 26;
SA();
Height();
LL res = (LL)n * (n + 1) / 2;
for (int i = 2; i <= n; i++)
res -= ht[i];
printf("%lld", res);
return 0;
}