[bzoj 3172--TJOI2013]单词

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

这道题是一道多串匹配,所以我们可以想到AC自动机。但是作为一个字符串萌新,感觉有点难度。
难点就是s的累加,那其实如果i是j的fail,那root到i就为j的一个后缀,那i.s就可以加上j.s,那这道题就解决了。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cstdlib>
using namespace std;
struct node
{
    int s,fail,c[27];
    node()
    {
        s=fail=0;
        memset(c,-1,sizeof(c));
    }
}t[1100000];
int tot,wy[210];
char ss[1100000];
void bt(int root,int id)
{
    int x=root;int len=strlen(ss+1);
    for(int i=1;i<=len;i++)
    {
        int y=ss[i]-'a';
        if(t[x].c[y]==-1)t[x].c[y]=++tot;
        x=t[x].c[y];t[x].s++;
    }
    wy[id]=x;
}
int list[1100000];
void getfail()
{
    int head=1,tail=1;
    list[1]=0;
    while(head<=tail)
    {
        int x=list[head];
        for(int i=0;i<26;i++)
        {
            int son=t[x].c[i];
            if(son==-1)continue;
            if(x==0)t[son].fail=0;
            else
            {
                int j=t[x].fail;
                while(j!=0 && t[j].c[i]==-1)j=t[j].fail;
                t[son].fail=max(t[j].c[i],0);
            }
            list[++tail]=son;
        }
        head++;
    }
    for(int i=tail;i>=1;i--)t[t[list[i]].fail].s+=t[list[i]].s;
}
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%s",ss+1),bt(0,i);
    getfail();
    for(int i=1;i<=n;i++)printf("%d\n",t[wy[i]].s);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章