bzoj 3172 [Tjoi2013]单词

来源:互联网 发布:数据作假 编辑:程序博客网 时间:2024/04/28 14:31

3172: [Tjoi2013]单词
Time Limit: 10 Sec Memory Limit: 512 MB
Submit: 3852 Solved: 1864
[Submit][Status][Discuss]
Description

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

Input

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

Output

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

Sample Input

3

a

aa

aaa

Sample Output

6

3

1

HINT


【分析】
• 构建单词的AC⾃自动机
• ⽂文章在⾃自动机上跑⼀一遍
• 在每个状态上打标记
• 对每个单词,在fail树的⼦子树中求和即可


【代码】

//bzoj 3172 [Tjoi2013]单词#include<queue>#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>#define ll long long#define fo(i,j,k) for(int i=j;i<=k;i++)using namespace std;const int mxn=1000010;queue <int> q;char s[mxn];int w[mxn],wxl[mxn],n,num,tot;struct node{    int son[30];    int fail,cnt;}a[mxn];inline void clear(int x){    memset(a[x].son,0,sizeof a[x].son);}inline void trie(int u){    int x=0,len=strlen(s);    fo(i,0,len-1)    {        int t=s[i]-'a'+1;        if(!a[x].son[t])        {            num++;            clear(num);            a[x].son[t]=num;        }        x=a[x].son[t];        a[x].cnt++;    }    w[u]=x;}inline void build(){    fo(i,1,26)      if(a[0].son[i])        q.push(a[0].son[i]);    while(!q.empty())    {        int x=q.front();        wxl[++tot]=x;        q.pop();        fo(i,1,26)        {            int y=a[x].son[i],fail=a[x].fail;            if(y)              a[y].fail=a[fail].son[i],q.push(y);            else              a[x].son[i]=a[fail].son[i];        }    }}int main(){    scanf("%d",&n);    fo(i,1,n)    {        scanf("%s",s);        trie(i);    }    build();    for(int i=tot;i;i--)      a[a[wxl[i]].fail].cnt+=a[wxl[i]].cnt;    fo(i,1,n) printf("%d\n",a[w[i]].cnt);    return 0;}
0 0