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

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

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 const int maxn = 1e6+5;
 4 struct word {
 5     string str;
 6     int num;  // 出现次数
 7     int pos;  // 出现位置 
 8 }words[maxn];
 9 bool cmp(word x, word y) {
10     if (x.num == y.num) return x.pos < y.pos;
11     return x.num > y.num;
12 }
13 struct Aho_Corasock_Automaton {
14     struct node {
15         int fail;  // 失配指针
16         int son[26];  // 子节点的位置
17         int end;  // 标记以该节点结尾的模式串的编号 
18     }Trie[maxn];
19     int cnt = 0; // Trie指针
20     void clear(int x) {  // 清空节点信息 
21         memset(Trie[x].son,0,sizeof(Trie[x].son));
22         Trie[x].fail = Trie[x].end = 0;
23     }
24     void insert(char *s, int num) {
25         int len = strlen(s);
26         int now = 0;  // Trie当前指针 
27         for (int i = 0; i < len; ++i) {
28             if (Trie[now].son[s[i]-'a'] == 0) { // 如果没有这个子节点 
29                 Trie[now].son[s[i]-'a'] = ++cnt;  // 构造该节点 
30                 clear(cnt);  // 清空新构造的节点里面的信息 
31             }
32             now = Trie[now].son[s[i]-'a']; 
33         }
34         Trie[now].end = num;  // 标记以该节点结尾是哪个模式串 
35     }
36     void get_fail() {  // 构造fail指针 
37         queue<int> que;
38         for (int i = 0; i < 26; ++i) {  // 先提前构造第二层 
39             if (Trie[0].son[i] != 0) {  // 如果存在该节点 
40                 Trie[Trie[0].son[i]].fail = 0;  // fail指向root节点 
41                 que.push(Trie[0].son[i]);  // 加入队列 
42             }
43         }
44         while (!que.empty()) {  // bfs求fail指针 
45             int u = que.front(); que.pop();
46             for (int i = 0; i < 26; ++i) {
47                 if (Trie[u].son[i] != 0) {  // 如果存在该子节点 
48                     // 子节点的fail指针指向当前节点的fail指针指向内容相同的子节点 
49                     Trie[Trie[u].son[i]].fail = Trie[Trie[u].fail].son[i];
50                     que.push(Trie[u].son[i]);  // 加入队列 
51                 }
52                 else {  // 如果不存在这个子节点 
53                     // 当前节点的该子节点指向当前节点的fail指针指向的止隔子节点 
54                     Trie[u].son[i] = Trie[Trie[u].fail].son[i];
55                 }
56             }
57         }
58     }
59     void query(char *s) {
60         int len = strlen(s);
61         int now = 0, ans = 0;  // 当前Trie指针,答案ans
62         for (int i = 0; i < len; ++i) {
63             now = Trie[now].son[s[i]-'a'];
64             for (int t = now; t != 0; t = Trie[t].fail) {  // 暴力搜索 
65                 words[Trie[t].end].num++;  // 以该节点为结尾的模式串次数加一 
66             }
67         }
68     }
69 }AC;
70 char t[maxn], s[maxn];
71 int main() {
72     int n;
73     while (scanf("%d",&n) != EOF && n) {
74         AC.cnt = 0, AC.clear(0);
75         for (int i = 1; i <= n; ++i) {
76             cin >> words[i].str;
77             strcpy(t,words[i].str.c_str());
78             words[i].pos = i;
79             words[i].num = 0;
80             AC.insert(t,i);        
81         }
82         AC.Trie[0].fail = 0;
83         AC.get_fail();
84         scanf("%s",s);
85         AC.query(s);
86         sort(words+1,words+1+n,cmp);
87         printf("%d\n%s\n",words[1].num,words[1].str.c_str());
88         for (int i = 2; i <= n; ++i) {
89             if (words[i].num == words[1].num) {
90                 printf("%s\n",words[i].str.c_str());
91             }
92             else break;
93         }
94     }
95     return 0;
96 }

 

posted @ 2019-10-20 21:58  麻辣猪仔  阅读(120)  评论(0)    收藏  举报