luogu 3796 【模板】AC自动机(加强版)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Tc_To_Top/article/details/84702336

题目描述

有N个由小写字母组成的模式串以及一个文本串T。每个模式串可能会在文本串中出现多次。你需要找出哪些模式串在文本串T中出现的次数最多。

输入输出格式

输入格式:

输入含多组数据。

每组数据的第一行为一个正整数N,表示共有N个模式串,1≤N≤150。

接下去N行,每行一个长度小于等于70的模式串。下一行是一个长度小于等于10^6的文本串T。

输入结束标志为N=0。

输出格式:

对于每组数据,第一行输出模式串最多出现的次数,接下去若干行每行输出一个出现次数最多的模式串,按输入顺序排列。

输入输出样例

输入样例#1:

2
aba
bab
ababababac
6
beta
alpha
haha
delta
dede
tata
dedeltalphahahahototatalpha
0

输出样例#1:

4
aba
2
alpha
haha

题目链接:https://www.luogu.org/problemnew/show/P3796

题目分析:常规操作

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <map>
#include <string>
#include <iostream>
using namespace std;
int const MAX = 1e6 + 5;
char s[MAX];

struct AC {
    int nxt[MAX][26], tot, root, fail[MAX];
    int end[MAX];
    pair<int, string> str[MAX];
    queue<int> q;
    

    int NewNode() {
        fail[tot] = 0;
        end[tot] = 0;
        str[tot].second = "";
        memset(nxt[tot], -1, sizeof(nxt[tot]));
        return tot++;
    }

    void Init() {
        tot = 0;
        root = NewNode();
    }

    void Insert(int id, char *s) {
        int p = root, len = strlen(s);
        for (int i = 0; i < len; i++) {
            int idx = s[i] - 'a';
            if (nxt[p][idx] == -1) {
                nxt[p][idx] = NewNode();
            }
            p = nxt[p][idx];
        }
        end[p]++;
        str[p] = make_pair(id, s);
    }

    void Build() {
        fail[root] = root;
        q.push(root);
        while (!q.empty()) {
            int p = q.front();
            q.pop();
            for (int i = 0; i < 26; i++) {
                if (nxt[p][i] == -1) {
                    nxt[p][i] = (p == root) ? root : nxt[fail[p]][i]; 
                } else {
                    fail[nxt[p][i]] = (p == root) ? root : nxt[fail[p]][i];
                    q.push(nxt[p][i]);
                }
            }
        }
    }

    void Query(char *s) {
        map< pair<int, string>, int> mp;
        map< pair<int, string>, int> :: iterator it;
        int len = strlen(s), cur = root;
        for (int i = 0; i < len; i++) {
            int idx = s[i] - 'a';
            while (nxt[cur][idx] == -1 && cur != root) {
                cur = fail[cur];
            }
            cur = nxt[cur][idx];
            int p = cur;
            while (p != root) {
                if (end[p]) {
                    mp[str[p]]++;
                }
                p = fail[p];
            }
        }
        int ma = 0;
        for (it = mp.begin(); it != mp.end(); it++) {
            ma = max(ma, it -> second);
        }
        printf("%d\n", ma);
        for (it = mp.begin(); it != mp.end(); it++) {
            if (it -> second == ma) {
                cout << (it -> first).second << endl;
            }
        }
    }
}ac;

int main() {
    int n;
    while (scanf("%d", &n) && n) {
        ac.Init();
        for (int i = 0; i < n; i++) {
            scanf("%s", s);
            ac.Insert(i, s);
        }
        ac.Build();
        scanf("%s", s);
        ac.Query(s);
    }
}

猜你喜欢

转载自blog.csdn.net/Tc_To_Top/article/details/84702336