【BZOJ 3172】[Tjoi2013]单词 Ac自动机

236 篇文章 0 订阅
11 篇文章 0 订阅

回顾了一下Ac自动机,额,顺便重新背个版,原来那个这道题要被卡

这道题题意有点模糊,意思就是要你找到每一个单词出现的次数,其中他可以作为其他单词的连续字串出现例如样例中a自己本身出现了一次在aa中出现2次aaa中出现3次一共6次,同理aa本身出现一次在aaa中出现2次一共3次。

解法比较裸,根据刚才的题意,所以每一个单词只要他能作为另外一个单词的一段就能对答案贡献为一而在Ac自动机中的fail树叶恰好可以解决这个问题,每插入一个单词就在trie数将沿途路径节点的值++,最后沿着fail指正从下到上更新过去就好了。只可意会。。。

#include<cstdio>
#include<cstring>
#include<iostream>
#define maxn 1000020
using namespace std;
int n,ch[maxn][26],sum[maxn],fail[maxn],sp[maxn],tot,q[maxn];
char s[maxn];

int insert(){
	int len=strlen(s),rt=0;
	for(int x,i=0;i<len;i++){
		x=s[i]-'a';
		if(!ch[rt][x])ch[rt][x]=++tot;
		sum[rt=ch[rt][x]]++;
	}	
	return rt;
}

void make(){
	int l=0,r=1,u;
	while(l<r){
		u=q[l++];
		for(int v,i=0;i<26;i++){
			v=ch[u][i];
			if(v)q[r++]=v,fail[v]=u==0?0:ch[fail[u]][i];
			else ch[u][i]=u==0?0:ch[fail[u]][i];
		}
	}
	for(int i=r-1;i;i--)sum[fail[q[i]]]+=sum[q[i]];
}


int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%s",s);
		sp[i]=insert();
	}
	make();
	for(int i=1;i<=n;i++)printf("%d\n",sum[sp[i]]);
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值