后缀自动机是一个能够接受母串所有后缀的最简自动机。
其中,每个节点代表一个字符串集合,该集合中所有的字符串均有相同的 \(right\) 集合。
各个节点之间根据 \(right\) 集合的关系可以组织成一棵树形结构,称为 \(parent\) 树。
后缀自动机最多有 \(2*n - 1\) 个节点。
代码如下
#include <bits/stdc++.h> using namespace std; struct SAM { struct state { int len, p, cnt; map<char, int> go; state(int _len = 0, int _p = -1, int _cnt = 0) { len = _len; p = _p; cnt = _cnt; } }; int last; vector<state> t; SAM() { last = 0; t.push_back({}); } inline state& operator[](int x) { return t[x]; } inline int size() { return t.size(); } inline void extend(char c) { int cur = t.size(); t.push_back({t[last].len + 1, -1, 1}); int x = last; while (x != -1 && t[x].go.count(c) == 0) { t[x].go[c] = cur; x = t[x].p; } if (x == -1) { t[cur].p = 0; } else { int y = t[x].go[c]; if (t[y].len == t[x].len + 1) { t[cur].p = y; } else { int z = t.size(); t.push_back(t[y]); t[z].len = t[x].len + 1; t[z].cnt = 0; while (x != -1 && t[x].go[c] == y) { t[x].go[c] = z; x = t[x].p; } t[cur].p = t[y].p = z; } } last = cur; } }; int main() { ios::sync_with_stdio(false); cin.tie(0), cout.tie(0); int n; string s; cin >> s; n = s.size(); SAM sam; for (int i = 0; i < n; i++) { sam.extend(s[i]); } vector<vector<int>> adj(sam.size()); for (int i = sam.size() - 1; i >= 1; i--) { adj[sam[i].p].push_back(i); } long long ans = 0; function<void(int)> dfs = [&](int u) { for (auto v : adj[u]) { dfs(v); sam[u].cnt += sam[v].cnt; } if (sam[u].cnt > 1) { ans = max(ans, (long long)sam[u].cnt * sam[u].len); } }; dfs(0); cout << ans << endl; return 0; }