P3804 【模板】后缀自动机 (SAM)

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;
这道题做法
前文提到可以预处理出每个节点中的子串在原串中出现的次数 f [ i ] f[i] ,所以我们枚举每个节点,对于每个节点,如果其 f [ i ] f[i] 不为1,则求其 t [ i ] = f [ i ] × l e n ( i ) t[i]=f[i]×len(i) t [ i ] m a x t[i]_{max} 即为答案。
其中注意clone的结点,的 f [ i ] f[i] 初始化为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;
}

发布了130 篇原创文章 · 获赞 80 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/KXL5180/article/details/103786215