题目大意:
有N 个由小写字母组成的模式串以及一个文本串T。
每个模式串可能会在文本串中出现多次。
你需要找出哪些模式串在文本串TT 中出现的次数最多。
1≤N≤150
模式串长度≤70
文本串T长度≤10^6
题解:
就是在这题的基础上改一下
http://blog.csdn.net/gx_man_vip/article/details/79556985
对于每个end[i]
(点i作为单词末位在所有单词中出现了多少次)
我们因为要记录次数,所以用rp[i]去每次找到时去累加end[i]。
然后每次存下单词末位在trie中的位置,
最后根据这些位置去找一个最大值
然后数组清空的问题呢,因为你的trie树数组很大,直接清空显然时间很不优美,所以我是对能拓展到的点才进行清零。
代码:
#include<bits/stdc++.h>
#define N 50010
using namespace std;
queue <int> Q;
int n,maxn,num,next[N][26],fail[N],end[N],rp[N],a[N];
char s[151][71],op[1000005];
void insert(int dep,char *s)
{
int len=strlen(s);
int u=0;
for (int i=0; i<len; i++)
{
int v=s[i]-'a';
if (!next[u][v])
{
next[u][v]=++num;
memset(next[num],0,sizeof(next[num]));
}
u=next[u][v];
}
end[u]++;
a[dep]=u;
}
void build()
{
fail[0]=0;
for (int i=0; i<26; i++)
if (next[0][i])
{
fail[next[0][i]]=0;
Q.push(next[0][i]);
}
while (!Q.empty())
{
int now=Q.front();
Q.pop();
for (int i=0; i<26; i++)
if (!next[now][i])
next[now][i]=next[fail[now]][i];
else {
fail[next[now][i]]=next[fail[now]][i];
Q.push(next[now][i]);
}
}
}
void query(char *s)
{
int len=strlen(s);
int now=0;
for (int i=0; i<len; i++)
{
int v=s[i]-'a';
now=next[now][v];
int u=now;
while (u!=0)
{
rp[u]=rp[u]+end[u];
u=fail[u];
}
}
}
int main()
{
scanf("%d",&n);
while (n)
{
memset(next[0],0,sizeof(next[0]));
for (int i=0; i<=num; i++)
{
rp[i]=0;
end[i]=0;
fail[i]=0;
}
num=0; maxn=0;
for (int i=1; i<=n; i++)
{
scanf("%s",s[i]);
insert(i,s[i]);
}
build();
scanf("%s",op);
query(op);
for (int i=1; i<=num; i++)
if (rp[i]>maxn) maxn=rp[i];
printf("%d\n",maxn);
for (int i=1; i<=n; i++)
if (rp[a[i]]==maxn) printf("%s\n",s[i]);
scanf("%d",&n);
}
return 0;
}