码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2018-04-21 17:37:44      阅读:143      评论:0      收藏:0      [点我收藏+]

标签:char s   amp   highlight   ring   ++   roo   family   rip   com   

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;//如果是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;
}

 

 

 

 

Solution

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

标签:char s   amp   highlight   ring   ++   roo   family   rip   com   

原文地址:https://www.cnblogs.com/void-f/p/8901847.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!