• 洛谷P3808 & P3796 AC自动机模板


    题目:P3808:https://www.luogu.org/problemnew/show/P3808

    P3796:https://www.luogu.org/problemnew/show/P3796

    从这里学了下AC自动机:http://www.cnblogs.com/cjyyb/p/7196308.html

    我的理解大概就是构建一棵由模式串组成的 Trie 树,然后把文本串一节一节放在上面查找;

    失配指针指向的是结尾字母和自己一样的、Trie 树上的其他分支,大约就是在找后缀这样的感觉;

    所以文本串每加入一个字符,就在 Trie 树上查找以这个字符结尾的后缀模式串,所以能找到所有出现过的;

    慕名已久的AC自动机原来也挺简单的嘛!

    代码如下:

    P3808:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    using namespace std;
    int const maxn=1e6+5;
    int n,cnt;
    queue<int>q;
    struct N{
        int fail,son[26],end;
    }AC[maxn];
    void build(string s)
    {
        int l=s.length();
        int nw=0;
        for(int i=0;i<l;i++)
        {
            if(AC[nw].son[s[i]-'a']==0)AC[nw].son[s[i]-'a']=++cnt;
            nw=AC[nw].son[s[i]-'a'];
        }
        AC[nw].end++;
    }
    void get_fail()
    {
        AC[0].fail=0;
        for(int i=0;i<26;i++)
        {
            if(AC[0].son[i]==0)continue;
            AC[AC[0].son[i]].fail=0;
            q.push(AC[0].son[i]);
        }
        while(q.size())
        {
            int x=q.front(); q.pop();
            for(int i=0;i<26;i++)
            {
                if(AC[x].son[i])
                {
                    AC[AC[x].son[i]].fail=AC[AC[x].fail].son[i];
                    q.push(AC[x].son[i]);
                }
                else AC[x].son[i]=AC[AC[x].fail].son[i];
            }
        }
    }
    int query(string s)
    {
        int l=s.length();
        int ret=0,nw=0;
        for(int i=0;i<l;i++)
        {
            nw=AC[nw].son[s[i]-'a'];
            for(int t=nw;t&&AC[t].end!=-1;t=AC[t].fail)
            {
                ret+=AC[t].end;
                AC[t].end=-1;
            }
        }
        return ret;
    }
    int main()
    {
        scanf("%d",&n);
        string s;
        for(int i=1;i<=n;i++)
        {
            cin>>s;
            build(s);
        }
        get_fail();
        cin>>s;
        printf("%d
    ",query(s));
        return 0;
    }

    P3796:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    using namespace std;
    int const maxn=1e6+5;
    int n,cnt;
    queue<int>q;
    string s[155];
    struct N{
        int son[26],fail,end;
    }AC[maxn];
    struct P{int num,pos;}ans[155];
    bool cmp(P x,P y)
    {
        if(x.num==y.num)return x.pos<y.pos;
        else return x.num>y.num;
    }
    void clear(int x)
    {
        memset(AC[x].son,0,sizeof AC[x].son);
        AC[x].fail=0; AC[x].end=0;
    }
    void build(string s,int num)
    {
        int l=s.length();
        int nw=0;
        for(int i=0;i<l;i++)
        {
            if(!AC[nw].son[s[i]-'a'])AC[nw].son[s[i]-'a']=++cnt,clear(cnt);
            nw=AC[nw].son[s[i]-'a'];
        }
        AC[nw].end=num;
    }
    void get_fail()
    {
        while(q.size())q.pop();
        AC[0].fail=0;
        for(int i=0;i<26;i++)
        {
            if(AC[0].son[i]==0)continue;
            AC[AC[0].son[i]].fail=0; q.push(AC[0].son[i]);
        }
        while(q.size())
        {
            int x=q.front(); q.pop();
            for(int i=0;i<26;i++)
            {
                if(AC[x].son[i])
                {
                    AC[AC[x].son[i]].fail=AC[AC[x].fail].son[i];
                    q.push(AC[x].son[i]);
                }
                else AC[x].son[i]=AC[AC[x].fail].son[i];
            }
        }
    }
    void query(string s)
    {
        int l=s.length();
        int nw=0;
        for(int i=0;i<l;i++)
        {
            nw=AC[nw].son[s[i]-'a'];
            for(int t=nw;t/*&&t.end!=-1*/;t=AC[t].fail)
            {
                ans[AC[t].end].num++;
    //            AC[t].end=-1;
            }
        }
    }
    int main()
    {
        while(1)
        {
            scanf("%d",&n);
            if(!n)return 0;
            cnt=0; clear(0);
            for(int i=1;i<=n;i++)
            {
                cin>>s[i];
                build(s[i],i);
                ans[i].pos=i;
                ans[i].num=0;//
            }
            get_fail();
            cin>>s[0];
            query(s[0]);
            sort(ans+1,ans+n+1,cmp);
            printf("%d
    ",ans[1].num);
            cout<<s[ans[1].pos]<<endl;
            for(int i=2;i<=n;i++)
            {
                if(ans[i].num==ans[i-1].num)
                    cout<<s[ans[i].pos]<<endl;
                else break;
            }
        }
    }
  • 相关阅读:
    JSON就是名值对 name/value pair
    AjaxXMLHttpRequest
    英语单词分类记
    委托和事件的理解
    用float设置主页的左右两边菜单
    OCS通讯路径
    测试用Word写Blog
    第一课 C#入门
    nginx虚拟目录设置 alias 和 root
    vsftp 出错,无法创建文件的解决方法
  • 原文地址:https://www.cnblogs.com/Zinn/p/9320998.html
Copyright © 2020-2023  润新知