CF1780G Delicious Dessert 题解
题意是求
虽然是 SAM 模版题,但是用 SA 也可以做,做法和 P3804 类似,核心是求出长度为
先求出
从大到小枚举值到
然后枚举
时间复杂度
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int INF = 0x3f3f3f3f;
const LL mod = 1e9 + 7;
const int N = 1000005;
int sa[N];
int rk[N << 1], tk[N << 1];
int height[N];
int id[N], cnt[N];
void SA(char *s, int n, int m) {
for (int i = 1; i <= n; i++) sa[i] = i, rk[i] = s[i];
for (int i = 0; i <= m; i++) cnt[i] = 0;
for (int i = 1; i <= n; i++) ++cnt[rk[i] = s[i]];
for (int i = 1; i <= m; i++) cnt[i] += cnt[i - 1];
for (int i = n; i >= 1; i--) sa[cnt[rk[i]]--] = i;
for (int w = 1; w < n; w *= 2) {
int p = 0;
for (int i = n - w + 1; i <= n; i++) id[++p] = i;
for (int i = 1; i <= n; i++) {
if (sa[i] > w) id[++p] = sa[i] - w;
}
for (int i = 1; i <= m; i++) cnt[i] = 0;
for (int i = 1; i <= n; i++) ++cnt[rk[i]];
for (int i = 1; i <= m; i++) cnt[i] += cnt[i - 1];
for (int i = n; i >= 1; i--) sa[cnt[rk[id[i]]]--] = id[i];
m = 0;
for (int i = 1; i <= n; i++) {
if (rk[sa[i]] == rk[sa[i - 1]] && rk[sa[i] + w] == rk[sa[i - 1] + w]) {
tk[sa[i]] = m;
} else {
tk[sa[i]] = ++m;
}
}
for (int i = 1; i <= n; i++) rk[i] = tk[i];
}
for (int i = 1, k = 0; i <= n; i++) {
if (rk[i] == 0) continue;
if (k) --k;
while (s[i + k] == s[sa[rk[i] - 1] + k]) ++k;
height[rk[i]] = k;
}
}
char s[N];
vector<int> a[N];
int sz[N], p[N], c[N];
int find(int x) {
return p[x] == x ? x : p[x] = find(p[x]);
}
int main() {
int n;
scanf("%d%s", &n, s + 1);
SA(s, n, 128);
for (int i = 1; i <= n; i++) {
p[i] = i, sz[i] = 1;
if (i > 1)
a[height[i]].push_back(i);
}
c[1] = n;
LL ans = 0;
for (int i = n; i >= 1; i--) {
for (auto x : a[i]) {
int y = find(x - 1);
x = find(x);
if (x != y) {
c[sz[x]]--;
c[sz[y]]--;
p[x] = y;
sz[y] += sz[x];
c[sz[y]]++;
}
}
for (int j = i; j <= n; j += i) {
ans += (LL)j * c[j];
}
}
printf("%lld\n", ans);
return 0;
}