https://www.luogu.com.cn/problem/P3804
很早以前就想把这个坑补了,最近终于把他补了。
后缀自动机是对一个字符串信息高度压缩后的产物。
这次把这个坑了补了。
建议从这些博客入门
https://www.cnblogs.com/xzyxzy/p/9186759.html
https://oi-wiki.org/string/sam/
https://www.luogu.com.cn/problemnew/solution/P3804
这些博客都写得很好,建议先看第一个博客理解基本概念,然后看第二个博客抄一遍代码。
在结合,洛谷第二篇题解那个构造图对照着代码走一遍。
这道题就是一个dp;
这道题做法
前文提到可以预处理出每个节点中的子串在原串中出现的次数
,所以我们枚举每个节点,对于每个节点,如果其
不为1,则求其
。
即为答案。
其中注意clone的结点,的
初始化为0;
#include "bits/stdc++.h"
using namespace std;
typedef long long ll;
const int maxn = 1000000 + 10;
const int inf = 0x3f3f3f3f;
ll ans = 0, d[maxn << 1];
struct state {
int len, link;
int next[26];
} st[maxn << 1];
int sz, last;
void init() {
st[0].len = 0;
st[0].link = -1;
sz++;
last = 0;
}
void extend(int c) {
int cur = sz++;
st[cur].len = st[last].len + 1;
d[cur] = 1;
int p = last;
while (p != -1 && !st[p].next[c]) {
st[p].next[c] = cur;
p = st[p].link;
}
if (p == -1) {
st[cur].link = 0;
} else {
int q = st[p].next[c];
if (st[p].len + 1 == st[q].len) {
st[cur].link = q;
} else {
int clone = sz++;
st[clone].len = st[p].len + 1;
memcpy(st[clone].next, st[q].next, sizeof(st[q].next));
st[clone].link = st[q].link;
while (p != -1 && st[p].next[c] == q) {
st[p].next[c] = clone;
p = st[p].link;
}
st[q].link = st[cur].link = clone;
}
}
last = cur;
}
struct edge {
int v, nxt;
} ed[maxn << 1];
int head[maxn << 1], cnt = 0, len;
void add(int u, int v) {
++cnt;
ed[cnt].v = v;
ed[cnt].nxt = head[u];
head[u] = cnt;
}
void dfs(int u) {
for (int i = head[u]; i; i = ed[i].nxt) {
dfs(ed[i].v);
d[u] += d[ed[i].v];
}
if (d[u] != 1)
ans = max(ans, d[u] * st[u].len);
}
char s[maxn];
int main() {
scanf("%s", s);
len = strlen(s);
init();
for (int i = 0; i < len; i++) extend(s[i] - 'a');
for (int i = 1; i < sz; i++) {
add(st[i].link, i);
}
dfs(0);
printf("%lld\n", ans);
return 0;
}