1. 程式人生 > >3065 【AC自動機】

3065 【AC自動機】

在一個串中找出給定子串出現的次數

#include<bits/stdc++.h>
#define cl(a) memset(a,0,sizeof(a))
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
char s[1005][150];
struct Trie
{
    int nxt[1005*55][128],fail[1005*55],ends[1005*55];
    int root,L;
    int newnode()
    {
        rep(i,0,127) nxt[L][i]=-1;
        fail[L]=-1;
        ends[L++]=-1;
        return L-1;
    }
    void init()
    {
        L=0;
        root = newnode();
    }
    void ins(char s[],int id)
    {
        int len = strlen(s);
        int now = root;
        rep(i,0,len-1)
        {
            if(nxt[now][s[i]]==-1)
            {
                nxt[now][s[i]]=newnode();
            }
            now=nxt[now][s[i]];
        }
        ends[now]=id;
    }

    void build()
    {
        queue<int>q;
        fail[root]=root;
        rep(i,0,127)
        {
            if(nxt[root][i]==-1)
            {
                nxt[root][i] = root;
            }
            else
            {
                fail[nxt[root][i]]=root;
                q.push(nxt[root][i]);
            }
        }
        while(!q.empty())
        {
            int now = q.front();
            q.pop();
            rep(i,0,127)
            {
                if(nxt[now][i]==-1)
                {
                    nxt[now][i]=nxt[fail[now]][i];
                }
                else
                {
                    fail[nxt[now][i]]=nxt[fail[now]][i];
                    q.push(nxt[now][i]);
                }
            }
        }
    }
    int num[1010];
    void query(char buf[],int n)
    {
        int len = strlen(buf);
        int now =root;
        for(int i=0; i<=n; i++)
        {
            num[i]=0;
        }
        //bool flag=false;
        rep(i,0,len-1)
        {
            now = nxt[now][buf[i]];
            int tmp = now;
            while(tmp!=root)
            {
                if(ends[tmp]!=-1)
                {
                    num[ends[tmp]]++;
                    //flag=true;
                }
                tmp=fail[tmp];
            }
        }
        rep(i,0,n-1)
        {
            if(num[i]>0) printf("%s: %d\n",s[i],num[i]);
        }
    }
};
char buf[2000005];
Trie ac;
int main()
{
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        ac.init();
        for(int i=0; i<n; i++)
        {
            scanf("%s",s[i]);
            ac.ins(s[i],i);
        }
        ac.build();
        scanf("%s",buf);
        ac.query(buf,n);
    }
    return 0;
}