【luogu P6139】【模板】广义后缀自动机(广义 SAM)
【模板】广义后缀自动机(广义 SAM)
题目链接:luogu P6139
题目大意
给你 n 个串,问你这里一共有多少个本质不同的子串。
思路
其实这道题我们只需要每次插入一个串之后插下一个串之间回到起点就可以了。
所以 SAM 还是普通的 SAM,求个数也是直接 \(len_i-len_{fa_i}\),没有什么太多少说的。
代码
#include<cstdio>
#include<cstring>
#define ll long long
using namespace std;
struct SAM {
int len, fa;
ll size;
int son[26];
}t[2000002];
int n, sn, tot, lst;
char s[1000001];
ll ans;
void SAM_insert(int now) {
int p = lst;
int np = ++tot;
lst = np;
t[np].size = 1;
t[np].len = t[p].len + 1;
for (; p && !t[p].son[now]; p = t[p].fa)
t[p].son[now] = np;
if (!p) t[np].fa = 1;
else {
int q = t[p].son[now];
if (t[q].len == t[p].len + 1) t[np].fa = q;
else {
int nq = ++tot;
t[nq] = t[q];
t[nq].size = 0;
t[nq].len = t[p].len + 1;
t[q].fa = t[np].fa = nq;
for (; p && t[p].son[now] == q; p = t[p].fa)
t[p].son[now] = nq;
}
}
}
int main() {
scanf("%d", &n);
tot = 1;
for (int i = 1; i <= n; i++) {
scanf("%s", s + 1);
sn = strlen(s + 1);
lst = 1;//每次重新回起点搞
for (int j = 1; j <= sn; j++)
SAM_insert(s[j] - 'a');
}
for (int i = 1; i <= tot; i++)
ans += t[i].len - t[t[i].fa].len;
printf("%lld", ans);
return 0;
}