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

来源:互联网 发布:altera用什么语言编程 编辑:程序博客网 时间:2024/04/28 15:50

题目描述

传送门

题解

将小串离线然后建立AC自动机
大串在自动机上直接匹配,能匹配的点标1
然后对于每一个点,如果它能匹配,那么它fail指向的点也能匹配
传递一下标记
然后对于每一个小串再查询一下前缀最多到哪里都匹配了

代码

#include<algorithm>#include<iostream>#include<cstring>#include<cstdio>#include<cmath>using namespace std;#define N 10000005int trans[100];char s[100005][105],S[N];int n,m,sz,cnt,l,r,ans,q[N],ch[N][4],fail[N];bool vis[N];void insert(char *s){    int len=strlen(s),now=0;    for (int i=0;i<len;++i)    {        int x=trans[s[i]];        if (!ch[now][x]) ch[now][x]=++sz;        now=ch[now][x];    }}void make_fail(){    l=0,r=0;    for (int i=0;i<4;++i)        if (ch[0][i]) q[++r]=ch[0][i];    while (l<r)    {        int now=q[++l];        for (int i=0;i<4;++i)        {            if (!ch[now][i])            {                ch[now][i]=ch[fail[now]][i];                continue;            }            fail[ch[now][i]]=ch[fail[now]][i];            q[++r]=ch[now][i];        }    }}void ac(){    int now=0;    for (int i=0;i<n;++i)    {        int x=trans[S[i]];        now=ch[now][x];        vis[now]=1;    }}void calc(char *s){    int len=strlen(s),now=0,dep=0;    for (int i=0;i<len;++i)    {        int x=trans[s[i]];        ++dep;        now=ch[now][x];        if (vis[now]) ans=max(ans,dep);    }}int main(){    trans['E']=0,trans['S']=1,trans['W']=2,trans['N']=3;    scanf("%d%d",&n,&m);    scanf("%s",S);    for (int i=1;i<=m;++i)    {        scanf("%s",s[i]);        insert(s[i]);    }    make_fail();    ac();    for (int i=r;i>=1;--i)    {        int now=q[i];        vis[fail[now]]|=vis[now];    }    for (int i=1;i<=m;++i)    {        ans=0;        calc(s[i]);        printf("%d\n",ans);    }}
0 0
原创粉丝点击