网址:https://www.luogu.org/problem/P3796
题意:
有$n$个由小写字母组成的模式串以及一个文本串$T$。每个模式串可能会在文本串中出现多次。你需要找出哪些模式串在文本串$T$中出现的次数最多。输入含多组数据。对于每组数据,第一行输出模式串最多出现的次数,接下去若干行每行输出一个出现次数最多的模式串,按输入顺序排列。
题解:
$AC$自动机板子题。和只寻找一次相比,取消路径上的已访问标记即可。
AC代码:
#include <iostream> #include <string> #include <map> #include <vector> #include <queue> #include <algorithm> #include <cstring> #include <cstdio> using namespace std; #define maxn int(1e6+9) int trie[maxn][26]; int cntword[maxn]; int fail[maxn]; int cnt = 0, strid = 0; struct stru { int num, pos; }; stru ans[200]; vector<string>input; struct ac { void insert(string& str) { int root = 0, next; for (int i = 0; i < str.size(); ++i) { next = str[i] - 'a'; if (!trie[root][next]) trie[root][next] = ++cnt; root = trie[root][next]; } cntword[root] = ++strid; } void buildfail() { queue<int>que; for (int i = 0; i < 26; ++i) if (trie[0][i]) { que.push(trie[0][i]); fail[trie[0][i]] = 0; } while (!que.empty()) { int now = que.front(); que.pop(); for (int i = 0; i < 26; ++i) { if (trie[now][i]) { fail[trie[now][i]] = trie[fail[now]][i]; que.push(trie[now][i]); } else trie[now][i] = trie[fail[now]][i]; } } } void query(string& str) { int now = 0; for (int i = 0; i < str.size(); ++i) { now = trie[now][str[i] - 'a']; for (int j = now; j ; j = fail[j]) { ++ans[cntword[j]].num; } } } }; bool cmp(const stru &a,const stru &b) { if (a.num == b.num) return a.pos < b.pos; return a.num > b.num; } int main() { string tmp; ac a; int n; while (cin >> n && n) { memset(trie, 0, sizeof(trie)); memset(fail, 0, sizeof(fail)); memset(cntword, 0, sizeof(cntword)); cnt = 0; strid = 0; input.clear(); for (int i = 1; i <= n; ++i) { ans[i].num = 0; ans[i].pos = i; cin >> tmp; input.push_back(tmp); a.insert(tmp); } a.buildfail(); cin >> tmp; a.query(tmp); sort(ans + 1, ans + n + 1, cmp); cout << ans[1].num << endl; for (int i = 1; ans[i].num == ans[1].num; ++i) cout << input[ans[i].pos - 1] << endl; } return 0; }