[BZOJ3172 ][Tjoi2013]单词(AC自动机)

Description

不稳定的传送门

某人读论文,一篇论文是由许多单词组成。但他发现一个单词会在论文中出现很多次,现在想知道每个单词分别在论文中出现多少次。
单词个数<=200,单词总长度<=10^6

Solution

AC自动机的入门题,将所有单词建一颗字典树,并构造fail树

然后随便统计一下数量就可以了

Code

 

#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;
		now=T[now][s[i]-96];
		T[now][0]++;
		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]);
	}
	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;
}

 

 

 

 

Solution

posted @ 2018-04-21 16:00  void_f  阅读(115)  评论(0编辑  收藏  举报