[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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章