题目链接: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; }