bzoj4327

AC自动机模板

i的fail指针指向j说明j的后缀一定在i的后缀中出现,对于每个点若访问过,则标记为1,

那然后建一条从j指向i的边,当j的子树中有被访问过时j的值也赋值为1(说明这个前缀在i中出现过)

/**************************************************************

    Problem: 4327

    User: syh0313

    Language: C++

    Result: Accepted

    Time:3792 ms

    Memory:494064 kb

****************************************************************/

 

#include <iostream>

#include <cstdio>

#include <cstdlib>

#include <cstring>

#include <string>

#include <cmath>

using namespace std;

const int maxn=10000100;

int n,m,root=1,cnt=1,head,tail,q[10000010];

string s[maxn],mu,ss;

int topt,to[maxn],st[maxn],nt[maxn];

struct data

{

    int c[4],v,fa,id;

}a[10000010];

void add(int x,int y)

{to[++topt]=y; nt[topt]=st[x]; st[x]=topt;}

int ok(char c)

{

    if (c=='E') return 0;

    if (c=='W') return 1;

    if (c=='S') return 2;

    if (c=='N') return 3;

return 0;

}

void insert(int num)

{

    int len=ss.length(); int now=root;

    for (int i=0;i<len;i++)

    {

        int x=ok(ss[i]);

        if (!a[now].c[x]) a[now].c[x]=++cnt;

        now=a[now].c[x];

    }

    a[now].id=num;

}

void getfail()

{

    head=1; tail=1; q[1]=root;

    while (head<=tail)

    {

        int now=q[head++];

        for (int i=0;i<=3;i++)

        {

            int to=a[now].c[i];

            if (!to) continue;

            if (now==root) a[to].fa=root,add(root,to);

            else

            {

                int father=a[now].fa;

                while (father)

                {

                    if (a[father].c[i])

                    {a[to].fa=a[father].c[i]; add(a[to].fa,to); break;}

                    father=a[father].fa;

                }

                if (!father) {a[to].fa=root; add(root,to);}

            }

            q[++tail]=to;

        }

    }

return;

}

void search()

{

    int len=mu.length(); int now=root;

    for (int i=0;i<len;i++)

    {

        int x=ok(mu[i]);

        while (!a[now].c[x] && now!=root) now=a[now].fa;

        if (now==root && !a[now].c[x]) continue;

        now=a[now].c[x];

        a[now].v=1;

    }

}

int work(int x)

{

    int p=st[x];

    while (p)

    {

        if (work(to[p])) a[x].v=1;

        p=nt[p];

    }

return a[x].v;

}

int find(string st)

{

    int len=st.length(); int now=root; int ans=0;

    for (int i=0;i<len;i++)

    {

        int x=ok(st[i]);

        if (a[a[now].c[x]].v==0) break;

        ans++;

        now=a[now].c[x];

    }

return ans;

}

int main()

{

    //freopen("1.in","r",stdin);

    //freopen("my.out","w",stdout);

    ios::sync_with_stdio(false);

    cin>>n>>m>>mu;

    for (int i=1;i<=m;i++) {cin>>ss; insert(i); s[i]=ss;}

    getfail();

    search();

    work(root);

    for (int i=1;i<=m;i++) printf("%d\n",find(s[i]));

return 0;      

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值