AC自动机
文本串中出现次数最多的模式串
//LA4670, 洛谷3796 %:pragma GCC optimize("Ofast", 2) #include <queue> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <iostream> #include <algorithm> using namespace std; #define maxn 12005 int t, n, m, len, ans; int cnt[155], fail[maxn]; int val[maxn], ch[maxn][26]; char text[1000005], s[155][80]; void init(){ ans = 0; memset(ch, 0, sizeof(ch)); fill(fail, fail+maxn, 0); fill(val, val+maxn, 0); fill(cnt, cnt+155, 0); } void s_insert(char *s, int v){ //构建字典树 int now, root = 0; len = strlen(s); for(int i = 0; i < len; i ++){ now = s[i]-'a'; if(!ch[root][now]){ ch[root][now] = ++ans; } root = ch[root][now]; } val[root] = v; } void get_fail(){ //获取失配指针 queue<int>Q; int u, now = 0; for(int i = 0; i < 26; i ++){ if(ch[now][i]){ //将模式串的首字母序号加入队列 Q.push(ch[now][i]); //fail[ch[now][i]] = 0; //last[ch[now][i]] = 0; } } while(!Q.empty()){ now = Q.front(); Q.pop(); for(int i = 0; i < 26; i ++){ u = ch[now][i]; if(u){ //当前序列存在 fail[u] = ch[fail[now]][i]; //失配指针指向其父节点失配指针指向节点的子节点 Q.push(ch[now][i]); }else{ ch[now][i] = ch[fail[now]][i]; //指向失配指针指向节点子节点 } } } } void query(char *text){ len = strlen(text); int now = 0; for(int i = 0; i < len; i ++){ now = ch[now][text[i]-'a']; for(int j = now; j; j = fail[j]){ cnt[val[j]]++; } } } int main(){ while(scanf("%d", &n) && n){ init(); for(int i = 1; i <= n; i ++){ scanf("%s", s[i]); s_insert(s[i], i); } scanf("%s", text); get_fail(); query(text); int res = 0; for(int i = 1; i <= n; i ++){ res = max(res, cnt[i]); } printf("%d\n", res); for(int i = 1; i <= n; i ++){ if(cnt[i] == res) printf("%s\n", s[i]); } } return 0; }