BZOJ4516[SDOI2016]生成魔咒(后缀数组/后缀自动机)

本文深入探讨了后缀自动机和后缀数组的构建过程及应用,通过实例解析,展示了如何使用这两种数据结构解决字符串匹配问题。特别介绍了后缀自动机的构建算法,并提供了详细的代码实现。

题目链接

洛谷

BZOJ

前置知识

后缀数组后缀自动机

前一个百度即可查获大量资料

后一个推荐hihocoder上的全套教程,题库搜索“后缀自动机”即可找到

解析

方法一:后缀数组

链接大法:https://blog.youkuaiyun.com/A_Comme_Amour/article/details/79987498

方法二:后缀自动机

回想构建后缀自动机的过程,不难发现每增加一个字符,增加的本质不同的子串就是\(new\_node->maxlen \ - \ new\_node->link->maxlen\)

而拆出来的点是不产生贡献的

构建自动机过程中统计答案即可

代码(后缀自动机)

学了3次后缀自动机,放个板子在这里以免又忘。。。。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <map>
#define MAXN 100005

typedef long long LL;
struct SuffixAutomaton {
    struct Node {
        Node *link;
        std::map<int, Node *> next;
        int maxlen;
    } * root, *last;
    LL ans;
    SuffixAutomaton() { last = root = new Node(); }
    Node *add(int);
    void build(int *, int);
} sam;
int N, a[MAXN], hash[MAXN], tot;

char gc();
LL read();
void print(LL);
void println(LL);
int main() {
    N = read();
    for (int i = 0; i < N; ++i)
        a[i] = read();
    sam.build(a, N);
}
inline char gc() {
    static char buf[1000000], *p1, *p2;
    if (p1 == p2) p1 = (p2 = buf) + fread(buf, 1, 1000000, stdin);
    return p1 == p2 ? EOF : *p2++;
}
inline LL read() {
    LL res = 0; char ch = gc();
    while (ch < '0' || ch > '9') ch = gc();
    while (ch >= '0' && ch <= '9')
        res = (res << 1) + (res << 3) + ch - '0', ch = gc();
    return res;
}
inline void print(LL x) {
    static int buf[30];
    if (!x) putchar('0');
    else {
        while (x) buf[++buf[0]] = x % 10, x /= 10;
        while (buf[0]) putchar('0' + buf[buf[0]--]);
    }
}
inline void println(LL x) { print(x); putchar('\n'); }
SuffixAutomaton::Node *SuffixAutomaton::add(int c) {
    Node *np = new Node(), *p = last;
    np->maxlen = last->maxlen + 1;
    while (p && !p->next.count(c)) p->next[c] = np, p = p->link;
    if (!p) np->link = root;
    else {
        Node *q = p->next[c];
        if (q->maxlen == p->maxlen + 1) np->link = q;
        else {
            Node *nq = new Node();
            nq->link = q->link, nq->maxlen = p->maxlen + 1, nq->next = q->next;
            q->link = np->link = nq;
            while (p && p->next[c] == q) p->next[c] = nq, p = p->link;
        }
    }
    return np;
}
void SuffixAutomaton::build(int *arr, int size) {
    for (int i = 0; i < size; ++i) last = add(arr[i]), println(ans = ans + last->maxlen - last->link->maxlen);
}

转载于:https://www.cnblogs.com/Rhein-E/p/10445032.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值