[TJOI2013]单词

题目描述

小张最近在忙毕设,所以一直在读论文。一篇论文是由许多单词组成但小张发现一个单词会在论文中出现很多次,他想知道每个单词分别在论文中出现了多少次。

输入格式

第一行一个整数N,表示有N个单词。接下来N行每行一个单词,每个单词都由小写字母(a-z)组成。(N≤200)

输出格式

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

输入 
3
a
aa
aaa
输出 
6
3
1

AC自动机板子题
~~QAQ我不会
反正大概思路就是你在建trie树时,将前缀累加
然后在跑fail树时,累加后缀
以上请遵循按深度大小
记录一下每个单词节点编号,差不多就得了
#include<bits/stdc++.h>
#define re return
#define inc(i,l,r) for(int i=l;i<=r;++i)
using namespace std;
template<typename T>inline void rd(T&x)
{
    char c;bool f=0;
    while((c=getchar())<'0'||c>'9')if(c=='-')f=1;
    x=c^48;
    while((c=getchar())>='0'&&c<='9')x=x*10+(c^48);
    if(f)x=-x;
}

const int maxn=1000005;
int n,m,tot,AC[maxn][26],fail[maxn],sum[maxn],ed[maxn];
char ss[1000005];
int q[1000005];
inline void build(int x)
{
    int len=strlen(ss);
    int now=0;
    inc(i,0,len-1)
    {
        if(!AC[now][ss[i]-'a'])
        AC[now][ss[i]-'a']=++tot;
        now=AC[now][ss[i]-'a'];
        ++sum[now];
    }    
    ed[x]=now;
}

inline void GET_fail()
{
    int hd=0,tail=0;
    inc(i,0,25)
    {
        if(AC[0][i])
        q[++tail]=AC[0][i];
    }
    
    while(hd<tail)
    {
        int u=q[++hd];
        inc(i,0,25)
        {
            if(AC[u][i])
            {
                fail[AC[u][i]]=AC[fail[u]][i];
                q[++tail]=AC[u][i]; 
            }
            else AC[u][i]=AC[fail[u]][i];
        }    
    }
    
    for(int i=tail;i>=1;--i)sum[fail[q[i]]]+=sum[q[i]];
    inc(i,1,n)
    printf("%d\n",sum[ed[i]]);
}
int main()
{
    freopen("in.txt","r",stdin);
    rd(n);
    inc(i,1,n)
    {
        scanf("%s",ss);
        build(i);
    } 
    
    GET_fail();
    re 0;
}

 

posted @ 2019-08-19 15:16  凉如水  阅读(174)  评论(0编辑  收藏  举报