SP705 SUBST1 - New Distinct Substrings题解
来交一个广义后缀自动机的题解。
这题需要用到一个后缀自动机的性质:设 \(minlen[i]\) 表示 \(i\) 节点所表示的 \(endpos\) 等价类中最短串的长度, \(len[i]\) 表示 \(i\) 节点所表示的 \(endpos\) 等价类中最长串的长度, \(fa[i]\) 表示 \(i\) 节点在 parent tree 上的父亲,则:
\[\begin{aligned}
minlen[i]=len[fa[i]]+1
\end{aligned}
\]
有了这个结论,这题就有解决方法了,一个 \(endpos\) 等价类 \(i\) 中本质不同的子串个数为 \(len[i]-minlen[i]+1\) ,并且不同的 \(endpos\) 等价类中所含子串一定不同,所以遍历所有 \(endpos\) 等价类,统计答案即可。
代码
// Problem: SP705 SUBST1 - New Distinct Substrings
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/SP705
// Memory Limit: 1500 MB
// Time Limit: 280 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include <bits/stdc++.h>
#define int long long
using namespace std;
namespace Std {
int k, n, ans;
char s[50010];
int fa[100010], len[100010], tot = 1, lst = 1, son[100010][26];
template <typename tp>
void read(tp &x);
template <typename tp>
void write(tp x);
void insert(int x);
void add(int x, int y);
void dfs(int x);
template <typename tp>
void read(tp &x) {
x = 0;
tp nev = 1;
char c = getchar();
while (c < '0' || c > '9') {
if (c == '-') nev = -1;
c = getchar();
}
while (c >= '0' && c <= '9') {
x = (x << 1) + (x << 3) + (c ^ 48);
c = getchar();
}
x *= nev;
}
template <typename tp>
void write(tp x) {
if (x < 0) {
putchar('-');
write(-x);
return;
}
if (x / 10) write(x / 10);
putchar((x % 10) ^ 48);
}
void insert(int x) {
int p = lst, np = lst = ++tot;
len[np] = len[p] + 1;
memset(son[np], 0, sizeof(son[np]));
while (p && (!son[p][x])) {
son[p][x] = np;
p = fa[p];
}
if (!p)
fa[np] = 1;
else {
int q = son[p][x];
if (len[q] == len[p] + 1)
fa[np] = q;
else {
int nq = ++tot;
memcpy(son[nq], son[q], sizeof(son[nq]));
fa[nq] = fa[q];
len[nq] = len[p] + 1;
fa[q] = fa[np] = nq;
while (p && son[p][x] == q) {
son[p][x] = nq;
p = fa[p];
}
}
}
}
int main(void) {
read(k);
while (k--) {
memset(son[1], 0, sizeof(son[1]));
scanf("%s", s + 1);
n = strlen(s + 1);
tot = lst = 1;
for (int i = 1; i <= n; ++i) insert(s[i] - 'a');
ans = 0;
for (int i = 2; i <= tot; ++i) {
ans += len[i] - len[fa[i]];
}
printf("%lld\n", ans);
}
return 0;
}
} // namespace Std
#undef int
int main(int argc, char *argv[]) { return Std::main(); }
未经授权,禁止转载。