不打算写太多的讲解了(其实是我也说不清楚 QwQ),这里只贴一份代码留着以后抄。
# 后缀数组(SA)
洛谷 P3809 【模板】后缀排序
#include <bits/stdc++.h> | |
using namespace std; | |
const int N = 1e6 + 10; | |
char s[N]; | |
int sa[N], rk[N], hei[N], x[N], y[N], cnt[N]; | |
int n, m = 127, tmp[N]; | |
inline void update(int Rk[], int tp[]){ | |
for(int i = 1; i <= m; ++i) cnt[i] = 0; | |
for(int i = 1; i <= n; ++i) cnt[Rk[tp[i]]]++; | |
for(int i = 1; i <= m; ++i) cnt[i] += cnt[i - 1]; | |
for(int i = n; i; --i) sa[cnt[Rk[tp[i]]]--] = tp[i]; | |
} | |
inline void build_sa(){ | |
int *Rk = rk, *tp = tmp; | |
for(int i = 1; i <= n; ++i) Rk[i] = s[i], tp[i] = i; | |
update(Rk, tp); | |
int p = 1; | |
for(int len = 1; p < n; m = p, len <<= 1){ | |
p = 0; | |
for(int i = n - len + 1; i <= n; ++i) tp[++p] = i; | |
for(int i = 1; i <= n; ++i) | |
if(sa[i] > len) tp[++p] = sa[i] - len; | |
update(Rk, tp); | |
swap(Rk, tp); | |
Rk[sa[1]] = p = 1; | |
for(int i = 2; i <= n; ++i) | |
Rk[sa[i]] = (tp[sa[i]] == tp[sa[i - 1]]) && (tp[sa[i] + len] == tp[sa[i - 1] + len]) ? p : ++p; | |
} | |
for(int i = 1; i <= n; ++i) rk[sa[i]] = i; | |
for(int i = 1, j = 0; i <= n; hei[rk[i++]] = j) | |
for(j = j ? j - 1 : j; s[i + j] == s[sa[rk[i] - 1] + j]; ++j); | |
} | |
int main(){ | |
scanf("%s", s + 1); | |
n = strlen(s + 1); | |
build_sa(); | |
for(int i = 1; i <= n; ++i) printf("%d%c", sa[i], "\n "[i != n]); | |
return 0; | |
} |
# 后缀自动机(SAM)
P3804 【模板】后缀自动机 (SAM)
#include <bits/stdc++.h> | |
#define ll long long | |
using namespace std; | |
namespace IO{ | |
inline int read(){ | |
int x = 0; | |
char ch = getchar(); | |
while(!isdigit(ch)) ch = getchar(); | |
while(isdigit(ch)) x = (x << 3) + (x << 1) + ch - '0', ch = getchar(); | |
return x; | |
} | |
template <typename T> inline void write(T x){ | |
if(x > 9) write(x / 10); | |
putchar(x % 10 + '0'); | |
} | |
} | |
using namespace IO; | |
const int N = 2e6 + 10; | |
int n, lst = 1, tot = 1; | |
int len[N], siz[N], ch[N][27], fa[N]; | |
char s[N]; | |
inline void insert(int c){ | |
int p = lst, np = ++tot; | |
lst = np; | |
len[np] = len[p] + 1, siz[np]++; | |
while(p && !ch[p][c]) ch[p][c] = np, p = fa[p]; | |
if(!p) return fa[np] = 1, void(); | |
int q = ch[p][c]; | |
if(len[q] == len[p] + 1) return fa[np] = q, void(); | |
int nq = ++tot; | |
len[nq] = len[p] + 1, fa[nq] = fa[q], siz[nq] = 0; | |
for(int i = 0; i < 26; ++i) ch[nq][i] = ch[q][i]; | |
while(p && ch[p][c] == q) ch[p][c] = nq, p = fa[p]; | |
fa[q] = fa[np] = nq; | |
} | |
vector <int> g[N]; | |
int ans = 0; | |
inline void dfs(int x){ | |
for(auto y : g[x]) dfs(y), siz[x] += siz[y]; | |
if(siz[x] > 1) ans = max(ans, siz[x] * len[x]); | |
} | |
int main(){ | |
scanf("%s", s + 1); | |
n = strlen(s + 1); | |
for(int i = 1; i <= n; ++i) insert(s[i] - 'a'); | |
for(int i = 2; i <= tot; ++i) g[fa[i]].push_back(i); | |
dfs(1); | |
write(ans), puts(""); | |
return 0; | |
} |