bzoj3172 [Tjoi2013]单词

http://www.elijahqi.win/archives/2888
Description

某人读论文,一篇论文是由许多单词组成。但他发现一个单词会在论文中出现很多次,现在想知道每个单词分别在论文中出现多少次。

Input

第一个一个整数N,表示有多少个单词,接下来N行每行一个单词。每个单词由小写字母组成,N<=200,单词长度不超过10^6

Output

输出N个整数,第i行的数字表示第i个单词在文章中出现了多少次。

Sample Input

3
a
aa
aaa
Sample Output

6
3
1
HINT

Source

这题主要还是利用了AC自动机fail树的一种性质 什么性质呢 就是我这个节点如果出现了 那么就会在我fail树上所有到根的路径上出现 那么不妨在构造AC自动机的时候 就给节点++ 然后反向建出fail树 然后dfs一下 即可得到答案 这次文章的意思是把给定的所有单词中间用特殊字符连接起来就是文章了..

#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 1010000
using namespace std;
int cnt=1;char s[N];int h[N],fail[N];
int trans[N][26],ans[N],num,end[220],n;
inline void insert1(char s[],int id){
    int len=strlen(s+1),p=1;
    for (int i=1,nxt;i<=len;++i){
        if (!trans[p][s[i]-'a']) trans[p][s[i]-'a']=nxt=++cnt;
        else nxt=trans[p][s[i]-'a'];p=nxt;++ans[p];
    }end[id]=p;
}
struct node{
    int y,next;
}data[N];
inline void insert1(int x,int y){
    data[++num].y=y;data[num].next=h[x];h[x]=num;
}
inline void dfs(int x){
    for (int i=h[x];i;i=data[i].next){
        int y=data[i].y;dfs(y);ans[x]+=ans[y];
    }
}
inline void buildAC(){
    queue<int>q;q.push(1);for (int i=0;i<26;++i) trans[0][i]=1;
    while(!q.empty()){
        int x=q.front();q.pop();
        for (int i=0;i<26;++i){
            int &y=trans[x][i];
            if (y) fail[y]=trans[fail[x]][i],q.push(y);
            else {y=trans[fail[x]][i];continue;}insert1(fail[y],y);
        }
    }
}
int main(){
//  freopen("bzoj3172.in","r",stdin);
    scanf("%d",&n);
    for (int i=1;i<=n;++i) scanf("%s",s+1),insert1(s,i);buildAC();dfs(1);
    for (int i=1;i<=n;++i) printf("%d\n",ans[end[i]]);
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值