题意:给n个字符串和一个文本串,输出出现次数最多的字符串
思路:AC自动机,构造Trie的时候,每个节点上的值就是那个字符串的下标加1,找到了可以匹配的时候直接对应的下标数量加1,在输出即可
#include<cstdio>
#include<cstring>
#include<queue>
#include<map>
#include<iostream>
#include<algorithm>
const int maxn = 1e6 + 10;
const int maxSize = 28;
using namespace std;
char t[maxn], p[200][100];
int f[maxn], last[maxn], np;
int ch[10600][maxSize], sz;
int val[maxn], num, mp[maxn];
void init() {
sz = 1; num = 0;
memset(mp, 0, sizeof(mp));
memset(ch[0], 0, sizeof(ch[0]));
memset(val, 0, sizeof(val));
memset(f, 0, sizeof(f));
}
void build(char *s, int ii) {
int u = 0, n = strlen(s);
for(int i = 0; i < n; i++) {
int c = s[i] - 'a' + 1;
if(!ch[u][c]) {
memset(ch[sz], 0, sizeof(ch[sz]));
ch[u][c] = sz++;
}
u = ch[u][c];
}
val[u] = ii;
}
void print(int i, int j) {
if(!j) return ;
///输出以模式串第i个位置结尾的所有可以匹配的给定字符串
///printf("%s --> %s\n", t + i - strlen(p[val[j] - 1]) + 1, p[val[j] - 1]);
mp[val[j] - 1]++;
num = max(num, mp[val[j] - 1]);
print(i, last[j]);
}
void getfail() {
queue<int> q;
f[0] = 0;
for(int c = 0; c < maxSize; c++) {
int u = ch[0][c];
if(u) { f[u] = 0; q.push(u); last[u] = 0; }
}
while(!q.empty()) {
int r = q.front(); q.pop();
for(int c = 0; c < maxSize; c++) {
int u = ch[r][c];
if(!u) continue;
q.push(u);
int v = f[r];
while(v && !ch[v][c]) v = f[v];
f[u] = ch[v][c];
last[u] = val[f[u]] ? f[u] : last[f[u]];
}
}
}
void Find(char *T) {
int n = strlen(T), j = 0;
for(int i = 0; i < n; i++) {
int c = T[i] - 'a' + 1;
while(j && !ch[j][c]) j = f[j];
j = ch[j][c];
if(val[j]) print(i, j);
else if(last[j]) print(i, last[j]);
}
}
int main() {
while(scanf("%d", &np) && np) {
init();
for(int i = 0; i < np; i++) {
scanf("%s", p[i]);
build(p[i], i + 1);
}
getfail();
scanf("%s", t);
Find(t);
cout << num << endl;
for(int i = 0; i < np; i++) {
if(mp[i] == num) cout << p[i] << endl;
}
}
return 0;
}