[JSOI2012]玄武密码 题解(AC自动机)

显然是AC自动机对吧

插入单词之后把文章在自动机上跑一遍,到达过的节点打上花火标记

之后检查一下每个单词有几个标记即可

可以把题目中的4个字母映射成abcd方便遍历

一定要记得把文章也映射啊!

#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
const int N=1e7+5;
char word[100005][105],s[N];
int n,m;
char mapping(char ch)
{
    switch(ch)
    {
        case 'E':return 'a';break;
        case 'S':return 'b';break;
        case 'W':return 'c';break;
        case 'N':return 'd';break;
    }
}
struct AC_auto
{
    struct node
    {
        node *son[7],*fail,*fa;
        int size;
        bool v;
        node()
        {
            memset(this,0,sizeof(node));
        }
    };
    node *root;
    void ini()
    {
        root=new node;
    }
    void ins(char *str)
    {
        int l=strlen(str+1);
        node *now=root;
        for(int i=1;i<=l;i++)
        {
            if(!now->son[str[i]-'a'])
                now->son[str[i]-'a']=new node();
            now=now->son[str[i]-'a'];
        }
        now->size++;
    }
    void build()
    {
        queue<node*> q;
        for(int i=0;i<4;i++)
        {
            if(root->son[i])
            {
                q.push(root->son[i]);
                root->son[i]->fail=root;
            }
            else root->son[i]=root;
        }
        while(!q.empty())
        {
            node *x=q.front();
            q.pop();
            for(int i=0;i<4;i++)
            {
                if(x->son[i])
                {
                    x->son[i]->fail=x->fail->son[i];
                    q.push(x->son[i]);
                }
                else x->son[i]=x->fail->son[i];
            }
            
        }
    }
    void query(char *str)
    {
        node *now=root;
        int l=strlen(str+1),i=1;
        while(i<=l)
        {
            now=now->son[str[i]-'a'];
            if(!now)return ;
            for(node *j=now;j!=root&&j->size!=-1;j=j->fail)
                j->size=-1;
            i++;
        }
    }
    int ans(char *str)
    {
        node *now=root;
        int l=strlen(str+1),i;
        for(i=1;i<=l;i++)
        {
            if(now->son[str[i]-'a']->size>=0)break;
            now=now->son[str[i]-'a'];
        }
        return i-1;
    }
}ac;
int main()
{
    scanf("%d%d%s",&n,&m,s+1);
    for(int i=1;i<=n;i++)s[i]=mapping(s[i]);//Don't forget it!
    ac.ini();
    for(int i=1;i<=m;i++)
    {
        scanf("%s",word[i]+1);
        int l=strlen(word[i]+1);
        for(int j=1;j<=l;j++)word[i][j]=mapping(word[i][j]);
        ac.ins(word[i]);
    }
    ac.build();
    ac.query(s);
    for(int i=1;i<=m;i++)printf("%d
",ac.ans(word[i]));
    return 0;
}
原文地址:https://www.cnblogs.com/Rorschach-XR/p/11021952.html