Luogu P3966 [TJOI2013]单词

题目链接 \(Click\) \(Here\)

本题\(AC\)自动机写法的正解之一是\(Fail\)树上跑\(DP\)

\(AC\)自动机是\(Trie\)树和\(Fail\)树共存的结构,前者可以方便地处理前缀问题,而在后者中,一个节点的子节点,代表以当前字符串为后缀的所有字符串节点(根节点外向\(Fail\)树)。我们最初给每个串的所有前缀计数\(+1\),后期统计时,在该前缀的所有后缀上(\(Fail\)树上的祖先节点上),将其自身答案累加上去,就是总共出现的次数。

#include <bits/stdc++.h>
using namespace std;

const int N = 1000010;

struct AC_Auto {
    int top, sta[N];
    long long sum[N];
    int cnt, ch[N][26], pre[N], fail[N];

    AC_Auto () {
        cnt = top = 0;
        memset (ch, 0, sizeof (ch));
        memset (sum, 0, sizeof (sum));
        memset (pre, 0, sizeof (pre));
        memset (fail, 0, sizeof (fail));
    }

    void add_str (char *s) {
        int l = strlen (s), now = 0;
        for (int i = 0; i < l; ++i) {
            if (!ch[now][s[i] - 'a']) {
                ch[now][s[i] - 'a'] = ++cnt;
            }
            pre[ch[now][s[i] - 'a']] = now;
            now = ch[now][s[i] - 'a'];
            sum[now]++;
        }
        sta[++top] = now;
    }

    queue <int> q;
    
    void build () {
        for (int i = 0; i < 26; ++i) {
            if (ch[0][i]) {
                q.push (ch[0][i]);
            }
        }
        while (!q.empty ()) {
            int u = q.front (); q.pop ();
            for (int i = 0; i < 26; ++i) {
                if (ch[u][i]) {
                    q.push (ch[u][i]);
                    fail[ch[u][i]] = ch[fail[u]][i];
                } else {
                    ch[u][i] = ch[fail[u]][i];
                }
            }
        }
    }

    int _cnt, head[N];

    struct edge {
        int nxt, to;
    }e[N];

    void add_edge (int from, int to) {
        e[++_cnt].nxt = head[from];
        e[_cnt].to = to;
        head[from] = _cnt;
    } 

    void dp (int u) {
        for (int i = head[u]; ~i; i = e[i].nxt) {
            dp (e[i].to);
            sum[u] += sum[e[i].to];
        }
    }
    
    void get_ans () {
        _cnt = 0;
        memset (head, -1, sizeof (head));
        for (int i = 1; i <= cnt; ++i) {
            add_edge (fail[i], i);
        }
        dp (0);
        for (int i = 1; i <= top; ++i) {
            cout << sum[sta[i]] << endl;
        }
    }
    
    
    
    
}AC;

int n; char s[N];

int main () {
    cin >> n;
    for (int i = 1; i <= n; ++i) {
        scanf ("%s", s);
        AC.add_str (s);
    }
    AC.build ();
    AC.get_ans ();
}

猜你喜欢

转载自www.cnblogs.com/maomao9173/p/10468748.html