洛谷 P3796 【模板】AC自动机(加强版)

题面

在这里插入图片描述

输入样例

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

输出样例

4
aba
2
alpha
haha

题意

  1. 其实还是AC自动机模板题(详解在HDU2222有讲),只要理解其核心ne数组,还是比较简单的,此题是让求单词在文章中出现的次数,并输出即可,这题要计算空间复杂度,开合适的大小。
  2. ne数组表示的是以某个点结尾的后缀所能匹配字典树中的最长前缀,那么我们在文章中进行单词匹配的过程,当有一个单词匹配成功后,那么这个单词所有的ne指向的位置,ne的ne指向的位置,都能匹配成功
  3. 这样,我们只需在插入的时候,标记一下每个单词结尾字母的节点编号,然后在文章匹配的过程中,每次匹配成功后,就通过刚才标记的节点编号来记录每个单词出现的次数,最后遍历一下最大的值输出即可

代码

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>

using namespace std;
const int N = 160, M = 1e6 + 10, K = 155 * 75;

int n;
char s[M];
string str[N];
int tr[K][26], cnt[K], idx;
int q[K], ne[K];
int id[K], res[N];
int maxn;

void insert(int x) {
    
    
    int p = 0;
    for (int i = 0; s[i]; i++) {
    
    
        int u = s[i] - 'a';
        if (!tr[p][u]) tr[p][u] = ++idx;
        p = tr[p][u];
    }
    cnt[p]++;
    id[p] = x; //标记一下每个单词结尾字母的节点编号
}

void build() {
    
    

    int hh = 0, tt = -1;
    for (int i = 0; i < 26; i++) {
    
    
        if (tr[0][i]) q[++tt] = tr[0][i];
    }

    while (hh <= tt) {
    
    
        int t = q[hh++];
        for (int i = 0; i < 26; i++) {
    
    
            int p = tr[t][i];
            if (!p) tr[t][i] = tr[ne[t]][i];
            else {
    
    
                ne[p] = tr[ne[t]][i];
                q[++tt] = p;
            }
        }
    }

}

int main() {
    
    

    while (cin >> n, n) {
    
    

        memset(tr, 0, sizeof tr);
        memset(cnt, 0, sizeof cnt);
        memset(ne, 0, sizeof ne);
        memset(id, 0, sizeof id);
        memset(res, 0, sizeof res);
        idx = 0, maxn = 0;

        for (int i = 1; i <= n; i++) {
    
    
            cin >> s;
            str[i] = s;
            insert(i);
        }

        build();

        cin >> s;

        for (int i = 0, j = 0; s[i]; i++) {
    
    
            int t = s[i] - 'a';
            j = tr[j][t];

            int p = j;
            while (p) {
    
    
                //通过节点编号找对应的单词,然后累加它出现的次数
                res[id[p]] += cnt[p];
                p = ne[p];
            }
        }
        for (int i = 1; i <= n; i++) maxn = max(res[i], maxn);

        cout << maxn << endl;
        for (int i = 1; i <= n; i++) {
    
    
            if (res[i] == maxn) {
    
    
                cout << str[i] << endl;
            }
        }
    }

    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_44791484/article/details/113802457