题目描述
有 NN 个由小写字母组成的模式串以及一个文本串 TT。每个模式串可能会在文本串中出现多次。你需要找出哪些模式串在文本串 TT 中出现的次数最多。
输入格式
输入含多组数据。保证输入数据不超过 5050 组。
每组数据的第一行为一个正整数 NN,表示共有 NN 个模式串,1 \leq N \leq 1501≤N≤150。
接下去 NN 行,每行一个长度小于等于 7070 的模式串。下一行是一个长度小于等于 10^6106 的文本串 TT。保证不存在两个相同的模式串。
输入结束标志为 N=0N=0。
输出格式
对于每组数据,第一行输出模式串最多出现的次数,接下去若干行每行输出一个出现次数最多的模式串,按输入顺序排列。
#include<iostream>
#include<algorithm>
#include<queue>
#include<cstring>
#include<cstdio>
using namespace std;
const int N=1e6+5;
int times[151],mx;
struct ACautomatic{
int tire[N][26];
int tail[N];
int fail[N];
int cnt;
void init()
{
cnt=0;
memset(tail,0,sizeof(tail));
memset(tire,0,sizeof(tire));
}
void insert(char *s,int id)
{
int len=strlen(s);
int p=0;
for(int i=0;i<len;i++)
{
if(tire[p][s[i]-'a']==0)tire[p][s[i]-'a']=++cnt;
p=tire[p][s[i]-'a'];
}
tail[p]=id;
}
void build()
{
memset(fail,0,sizeof(fail));
queue<int> que;
for(int i=0;i<26;i++)if(tire[0][i])que.push(tire[0][i]);
while(!que.empty())
{
int v=que.front();que.pop();
for(int i=0;i<26;i++)
{
if(tire[v][i])
{
fail[tire[v][i]]=tire[fail[v]][i];
que.push(tire[v][i]);
}
else tire[v][i]=tire[fail[v]][i];
}
}
}
void search(char *s)
{
int len=strlen(s);
int p=0;
for(int i=0;i<len;i++)
{
p=tire[p][s[i]-'a'];
for(int j=p;j;j=fail[j])
if(tail[j]){
times[tail[j]]++;
if(times[tail[j]]>mx)mx=times[tail[j]];
}
}
}
}ac;
int main()
{
int t,n;
scanf("%d",&n);
while(n!=0)
{
ac.init();
memset(times,0,sizeof(times));
mx=0;
char str[151][75];
for(int i=1;i<=n;i++)
{
scanf("%s",str[i]);
ac.insert(str[i],i);
}
ac.build();
char s[1000005];
scanf("%s",s);
ac.search(s);
printf("%d\n",mx);
for(int i=1;i<=n;i++)
if(times[i]==mx)puts(str[i]);
scanf("%d",&n);
}
}