emm。。。AC自动机加强版?
还是没啥变化。。。QVQ
相较于简单版,模板没有丝毫改变
只是这次要记录下那个子串是出现最多的就好了。。。QVQ
为了方便,我们可以直接用 string 类型
然鹅 string 类型的数组是不leng用 scanf 读的。。。QVQ
所以代码跑的巨慢。。。
呆码:
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<queue> #include<algorithm> using namespace std; string s[100010]; int cnt=0; struct asd{ int fail;//失配指针 int vis[26];//子节点的位置 int end;//标记以这个节点结尾的单词编号 } AC[100010];//Trie树 struct sdf{ int num; int pos; } ans[100010];//所有单词的出现次数 inline void insert(string s,int num) { int l=s.length(); int now=0; // 字典树的当前指针 for(int i=0;i<l;++i) // 构造Trie树 { if(AC[now].vis[s[i]-'a']==0) // Trie树没有这个子节点 { AC[now].vis[s[i]-'a']=++cnt; // 构造出来 } now=AC[now].vis[s[i]-'a']; // 向下构造 } AC[now].end=num; // 标记单词结尾 } inline void get_fail() // 构造fail指针 { queue<int> Q; // 队列 for(int i=0;i<=25;++i) // 第二层的fail指针提前处理一下 if(AC[0].vis[i]!=0) Q.push(AC[0].vis[i]);//压入队列 while(!Q.empty()) // BFS求fail指针 { int u=Q.front(); Q.pop(); for(int i=0;i<=25;++i) // 枚举所有子节点 { if(AC[u].vis[i]!=0) // 存在这个子节点 { AC[AC[u].vis[i]].fail=AC[AC[u].fail].vis[i]; // 子节点的fail指针指向当前节点的 // fail指针所指向的节点的相同子节点 Q.push(AC[u].vis[i]); // 压入队列 } else // 不存在这个子节点 AC[u].vis[i]=AC[AC[u].fail].vis[i]; // 当前节点的这个子节点指向当 // 前节点fail指针的这个子节点 } } } inline void query(string s) // AC自动机匹配 { int l=s.length(); int now=0; for(int i=0;i<l;++i) { now=AC[now].vis[s[i]-'a']; // 向下一层 for(int j=now;j;j=AC[j].fail) // 循环求解 ans[AC[j].end].num++; } } inline bool cmp(sdf x,sdf y) { if(x.num==y.num) return x.pos<y.pos; else return x.num>y.num; } int main() { int n; while(1) { cin>>n; cnt=0; if(n==0) break; memset(AC,0,sizeof(AC)); for(int i=1;i<=n;++i) { cin>>s[i]; ans[i].num=0; ans[i].pos=i; insert(s[i],i); } get_fail();//求出失配指针 cin>>s[0]; query(s[0]); sort(ans+1,ans+1+n,cmp); printf("%d ",ans[1].num); cout<<s[ans[1].pos]<<endl; for(int i=2;i<=n;++i) { if(ans[i].num==ans[i-1].num) cout<<s[ans[i].pos]<<endl; else break; } } return 0; }