标签:char s amp highlight ring ++ roo family rip com
某人读论文,一篇论文是由许多单词组成。但他发现一个单词会在论文中出现很多次,现在想知道每个单词分别在论文中出现多少次。
单词个数<=200,单词总长度<=10^6
AC自动机的入门题,将所有单词建一颗字典树,并构造fail树
然后随便统计一下数量就可以了
#include <cstdio> #include <algorithm> #include <cstring> #define R register #define N 1000002 using namespace std; char s[N]; int n,T[N][27],fail[N],e[N][2],head[N],q[N],tot,h,t,num=1,wr[201]; inline void Insert(int k){ int len=strlen(s); for(R int now=1,i=0;i<len;++i){ if(T[now][s[i]-96]==0) T[now][s[i]-96]=++num;//如果是num++,num必须初始化为2,因为root为1,否则会RE now=T[now][s[i]-96]; T[now][0]++;//此前缀数量+1 if(i==len-1) wr[k]=now; } } inline void Link(int u,int v){ e[++tot][0]=v,e[tot][1]=head[u],head[u]=tot; } inline void getfail(){ int k,now; h=0,t=1;q[1]=1; while(h<t){ now=q[++h]; for(R int i=1;i<=26;++i) if(T[now][i]!=0){ k=fail[now]; while(k!=0&&T[k][i]==0) k=fail[k]; if(T[k][i]!=0) fail[T[now][i]]=T[k][i]; else fail[T[now][i]]=1; Link(fail[T[now][i]],T[now][i]); q[++t]=T[now][i]; } } } inline int calc(int k){ for(R int j=head[k];j;j=e[j][1]){ T[k][0]+=calc(e[j][0]);//fail树上所有子结点数量和 } return T[k][0]; } int main(){ scanf("%d",&n); T[1][0]=1; for(R int i=1;i<=n;++i){ scanf("%s",s); Insert(i); } getfail(); calc(1); for(R int i=1;i<=n;++i) printf("%d\n",T[wr[i]][0]); return 0; }
[BZOJ3172 ][Tjoi2013]单词(AC自动机)
标签:char s amp highlight ring ++ roo family rip com
原文地址:https://www.cnblogs.com/void-f/p/8901847.html