【模板】AC自动机

忘了博客地址了。
后续可能上升为总结。
代码比较复杂,细节很多,建议背下来。

【模板】AC自动机(简单版)
由势能分析可知,Query 部分时间复杂度是 O ( 2 ∗ l e n T ) O(2*lenT) O(2lenT)
统计 f a i l fail fail 答案部分是长度和,因为只统计是否出现。

#include<bits/stdc++.h> using namespace std; const int MAXC=26; const int N=1e6+5; struct node{ int cnt,fail,nxt[MAXC]; }t[N]; int root,tot=1,res=0,T,n; queue<int> Q; char article[N],word[N]; void insert(char *s) { int len=strlen(s),r=1; for(int i=0;i<len;i++) { if(!t[r].nxt[s[i]-'a']) t[r].nxt[s[i]-'a']=++tot; r=t[r].nxt[s[i]-'a']; } t[r].cnt++; } void build() {//AcMachine t[1].fail=1; Q.push(1); while(Q.size()) {//order in depth int r=Q.front();Q.pop(); for(int i=0;i<MAXC;i++) { int ch=t[r].nxt[i],p; if(ch) { Q.push(ch); for(p=t[r].fail;p!=1&&t[p].nxt[i]==0;p=t[p].fail); int tmp=t[p].nxt[i]; if(tmp&&tmp!=ch) t[ch].fail=tmp; else t[ch].fail=1; } } } } void Query(char *s) { int r=1,len=strlen(s); for(int i=0;i<len;i++) { int p; for(p=r;p!=1&&t[p].nxt[s[i]-'a']==0;p=t[p].fail); r=t[p].nxt[s[i]-'a']; if(r==0) r=1; for(int temp=r;temp!=1;temp=t[temp].fail) { if(t[temp].cnt==-1) break; res+=t[temp].cnt; t[temp].cnt=-1; } } } int main() { // freopen("1.in","r",stdin); scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%s",word); insert(word); } // printf("yes"); scanf("%s",article); build(); // for(int i=1;i<=tot;i++) printf("fail[%d]=%d\n",i,t[i].fail); Query(article); printf("%d",res); }

【模板】AC自动机(二次加强版)
区别只在于加了一个 t o p o topo topo 排序。

#include<bits/stdc++.h> using namespace std; const int MAXC=26; const int N=2e6+5; struct node{ int cnt,end,fail,nxt[MAXC]; }t[N]; int root,tot=1,res=0,T,n,ans[N]; int c[N]; int in[N]; queue<int> Q; char article[N],word[N]; int insert(char *s) { int len=strlen(s),r=1; for(int i=0;i<len;i++) { if(!t[r].nxt[s[i]-'a']) t[r].nxt[s[i]-'a']=++tot; r=t[r].nxt[s[i]-'a']; } t[r].end=1; return r; } void build() {//AcMachine t[1].fail=1; Q.push(1); while(Q.size()) {//order in depth int r=Q.front();Q.pop(); for(int i=0;i<MAXC;i++) { int ch=t[r].nxt[i],p; if(ch) { Q.push(ch); for(p=t[r].fail;p!=1&&t[p].nxt[i]==0;p=t[p].fail); int tmp=t[p].nxt[i]; if(tmp&&tmp!=ch) t[ch].fail=tmp; else t[ch].fail=1; } } } } void Query(char *s) { int r=1,len=strlen(s); for(int i=0;i<len;i++) { int p; for(p=r;p!=1&&t[p].nxt[s[i]-'a']==0;p=t[p].fail); r=t[p].nxt[s[i]-'a']; if(r==0) r=1; t[r].cnt++; // for(int temp=r;temp!=1;temp=t[temp].fail) { // if(t[temp].cnt==-1) break; // res+=t[temp].cnt; // t[temp].cnt++; // } } } int main() { // freopen("1.in","r",stdin); scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%s",word); ans[i]=insert(word); } // printf("yes"); scanf("%s",article); build(); // for(int i=1;i<=tot;i++) printf("fail[%d]=%d\n",i,t[i].fail); Query(article); while(Q.size()) Q.pop(); for(int i=1;i<=tot;i++) in[t[i].fail]++; for(int i=1;i<=tot;i++) if(!in[i]) Q.push(i); while(Q.size()) { int x=Q.front();Q.pop(); t[t[x].fail].cnt+=t[x].cnt; if(--in[t[x].fail]==0) Q.push(t[x].fail); } for(int i=1;i<=n;i++) printf("%d\n",t[ans[i]].cnt); }

__EOF__

本文作者仰望星空的蚂蚁
本文链接https://www.cnblogs.com/cqbzly/p/17530376.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   仰望星空的蚂蚁  阅读(6)  评论(0编辑  收藏  举报  
编辑推荐:
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」
点击右上角即可分享
微信分享提示