题目链接:https://www.luogu.org/problem/P3796
题意:求在文本串中模式串出现的最多次数,并输出这些次数最多的模式串。这题和luoguP3808一样,稍微改一下就行。
思路:令key表示以该结点结尾的字符串的下标(前提是所有模式串不相同)即可。query中循环查找时将贡献加上即可。
AC code:
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
#include<cstdlib>
using namespace std;
const int maxn=1e6+5;
char s1[155][100],s2[maxn];
int n,ans[155],cnt=0,Max;
int fail[maxn],trie[maxn][30],key[maxn];
void build(char *s,int k){
int len=strlen(s),u=0;
for(int i=0;i<len;++i){
int t=s[i]-'a';
if(!trie[u][t]){
++cnt;
memset(trie[cnt],0,sizeof(trie[cnt]));
fail[cnt]=0,key[cnt]=0;
trie[u][t]=cnt;
}
u=trie[u][t];
}
key[u]=k;
}
void get_fail(){
queue<int> que;
for(int i=0;i<26;++i){
if(trie[0][i]){
fail[trie[0][i]]=0;
que.push(trie[0][i]);
}
}
while(!que.empty()){
int u=que.front();que.pop();
for(int i=0;i<26;++i){
if(trie[u][i]){
fail[trie[u][i]]=trie[fail[u]][i];
que.push(trie[u][i]);
}
else{
trie[u][i]=trie[fail[u]][i];
}
}
}
}
void query(char *s){
int len=strlen(s),u=0;
for(int i=0;i<len;++i){
int t=s[i]-'a';
u=trie[u][t];
for(int j=u;j;j=fail[j])
++ans[key[j]];
}
}
int main(){
while(scanf("%d",&n),n){
cnt=0,Max=0;
for(int i=1;i<=n;++i)
ans[i]=0;
memset(trie[0],0,sizeof(trie[0]));
for(int i=1;i<=n;++i){
scanf("%s",s1[i]);
build(s1[i],i);
}
fail[0]=0;
get_fail();
scanf("%s",s2);
query(s2);
for(int i=1;i<=n;++i)
Max=max(Max,ans[i]);
printf("%d\n",Max);
for(int i=1;i<=n;++i)
if(ans[i]==Max)
printf("%s\n",s1[i]);
}
return 0;
}