hdoj3065(AC自动机简单题)
题目链接:https://vjudge.net/problem/HDU-3065
题意:给定n个不相同的模式串,模式串总长<=5e4。给定文本串,长度<=2e6。求各个模式串在文本串中出现次数。
思路:
AC自动机简单题。因为要输出次数,所以用到了拓扑排序优化版本的AC自动机。用key[u]表示以u结点结束的模式串编号,res[u]表示文本中以u为结尾的次数(拓扑排序优化版本中不用沿fail循环,那样会T),用in[u]表示入度。
另外这题是多组输入,比较坑!
AC code:
#include<cstdio> #include<cstring> #include<algorithm> #include<queue> using namespace std; const int maxt=5e4+5; const int maxn=1e3+5; int n,cnt,trie[maxt][130],key[maxt],res[maxt],in[maxt],fail[maxt]; int ans[maxn]; char s[maxn][55],ss[2000005]; void build(char *s,int k){ int len=strlen(s),u=0; for(int i=0;i<len;++i){ int t=s[i]; if(!trie[u][t]){ ++cnt; memset(trie[cnt],0,sizeof(trie[cnt])); key[cnt]=0,fail[cnt]=0,res[cnt]=0,in[cnt]=0; trie[u][t]=cnt; } u=trie[u][t]; } key[u]=k; } void get_fail(){ queue<int> que; for(int i=0;i<130;++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<130;++i){ if(trie[u][i]){ fail[trie[u][i]]=trie[fail[u]][i]; ++in[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]; u=trie[u][t]; ++res[u]; } } void topu(){ queue<int> que; for(int i=1;i<=cnt;++i) if(!in[i]) que.push(i); while(!que.empty()){ int u=que.front();que.pop(); ans[key[u]]+=res[u]; int v=fail[u]; --in[v]; res[v]+=res[u]; if(!in[v]) que.push(v); } } int main(){ while(~scanf("%d",&n)){ memset(trie[0],0,sizeof(trie[0])); key[0]=0,res[0]=0,in[0]=0; cnt=0; for(int i=1;i<=n;++i) ans[i]=0; for(int i=1;i<=n;++i){ scanf("%s",s[i]); build(s[i],i); } fail[0]=0; get_fail(); scanf("%s",ss); query(ss); topu(); for(int i=1;i<=n;++i) if(ans[i]) printf("%s: %d\n",s[i],ans[i]); } return 0; }
朋友们,无论这个世界变得怎样,只要能够为了当时纯粹的梦想和感动坚持努力下去,不管其它人怎么样,我们也能够保持自己的本色走下去。