AC自动机-洛谷3121 [USACO15FEB]审查(黄金)Censoring (Gold)

来源:互联网 发布:大趋势炒股软件 编辑:程序博客网 时间:2024/06/05 19:38

https://www.luogu.org/problem/show?pid=3121#sub
首先题目看清楚

FJ注意到列表中的单词不会出现一个单词是另一个单词子串的情况,这意味着每个列表中的单词在S中出现的开始位置是互不相同的

这意味着你在找答案时,当一个节点正常访问的时候,你不用去寻找fail;
你只要在匹配失败的时候取fail就好了;
关于fail的意义,可以看我AC自动机的博客;
然后我们在造trie时,顺便把一个字符串的长度记录下来;
end=一个字符串的长度;
然后我们开2个栈;
a[]记录当前搜到那个点;
b[]记录当前搜那个char;
然后如果发现当前节点是end;
直接弹出栈顶end个元素;
更新now指针,继续搜;
好了;
有个事情要注意;
我原始的AC自动机;

void makezyy(){    for(int i=0;i<26;i++)if(T[0].nxt[i])q[++r]=T[0].nxt[i];    while(r>l){        int x=q[++l];        for(int i=0;i<26;i++)if(T[x].nxt[i]){            q[++r]=T[x].nxt[i];            int y=T[x].fail;            while(y&&!T[y].nxt[i])y=T[y].fail;            T[q[r]].fail=T[y].nxt[i];        }    }}void find(int m){    int o=0;    for(int i=0;i<m;i++){        int x=s[i]-'a';        int y=o;        while(y&&!T[y].nxt[x])y=T[y].fail;        o=T[y].nxt[x];        a[++tot]=o;        b[tot]=i;        if(T[o].E){            tot-=T[o].E;            o=a[tot];        }        }}

大家看,这个好理解,但是用了while循环,会被卡一个点;
那我们看看更优的写法;

void makezyy(){    for(int i=0;i<26;i++)if(T[0].nxt[i])q[++r]=T[0].nxt[i];    while(r>l){        int x=q[++l];        for(int i=0;i<26;i++)            if(!T[x].nxt[i])T[x].nxt[i]=T[T[x].fail].nxt[i];            else{                q[++r]=T[x].nxt[i];                T[T[x].nxt[i]].fail=T[T[x].fail].nxt[i];            }    }}void find(int m){    int o=0;    for(int i=0;i<m;i++){        o=T[o].nxt[s[i]-'a'];        a[++tot]=o;        b[tot]=i;        if(T[o].E){            tot-=T[o].E;            o=a[tot];        }       }}

种方法巧妙地运用地推;
两种方法求出的fail值是相同的;
但是这种方法会无法辨别出某个节点在一开始有没有某个儿子;
因为makezyy之后空的儿子自动变成了fail;
好像还可以优化的吧;

#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>using namespace std;struct trie{    int nxt[26],fail,E;}T[100005];int q[100005],l,r,a[100005],b[100005],tot;int n,m,ll;char s[100005],c[100005];void init(int m){    int o=0;    for(int i=0;i<m;i++){        int x=c[i]-'a';        if(!T[o].nxt[x])T[o].nxt[x]=++ll;        o=T[o].nxt[x];    }T[o].E=m;}void makezyy(){    for(int i=0;i<26;i++)if(T[0].nxt[i])q[++r]=T[0].nxt[i];    while(r>l){        int x=q[++l];        for(int i=0;i<26;i++)            if(!T[x].nxt[i])T[x].nxt[i]=T[T[x].fail].nxt[i];            else{                q[++r]=T[x].nxt[i];                T[T[x].nxt[i]].fail=T[T[x].fail].nxt[i];            }    }}void find(int m){    int o=0;    for(int i=0;i<m;i++){        o=T[o].nxt[s[i]-'a'];        a[++tot]=o;        b[tot]=i;        if(T[o].E){            tot-=T[o].E;            o=a[tot];        }       }}int main(){    scanf("%s",s);    scanf("%d",&n);    while(n--)scanf("%s",c),init(strlen(c));    makezyy();    find(strlen(s));    for(int i=1;i<=tot;i++)cout<<s[b[i]];}
1 0
原创粉丝点击