zoukankan      html  css  js  c++  java
  • [模板] AC自动机

    这是一道简单版的AC自动机,之前我搞过一个这个东西,但是没具体学习,现在来学一下。

    其实就是一个trie树上跑的kmp,每个节点存一个fail指针,指向前一次出现的地方。查询的时候直接加一起就行了。

    题干:

    题目背景
    通过套取数据而直接“打表”过题者,是作弊行为,发现即棕名。
    
    这是一道简单的AC自动机模板题。
    
    用于检测正确性以及算法常数。
    
    为了防止卡OJ,在保证正确的基础上只有两组数据,请不要恶意提交。
    管理员提示:本题数据内有重复的单词,且重复单词应该计算多次,请各位注意
    题目描述
    给定n个模式串和1个文本串,求有多少个模式串在文本串里出现过。
    输入输出格式
    输入格式:
    第一行一个n,表示模式串个数;
    下面n行每行一个模式串;
    下面一行一个文本串。
    输出格式:
    一个数表示答案
    输入输出样例
    输入样例#1: 复制
    2
    a
    aa
    aa
    输出样例#1: 复制
    2
    说明
    subtask1[50pts]:∑length(模式串)<=10^6,length(文本串)<=10^6,n=1;
    subtask2[50pts]:∑length(模式串)<=10^6,length(文本串)<=10^6

    代码:

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<ctime>
    #include<queue>
    #include<algorithm>
    #include<string>
    #include<cstring>
    using namespace std;
    #define duke(i,a,n) for(ll i = a;i <= n;i++)
    #define lv(i,a,n) for(int i = a;i >= n;i--)
    #define clean(a) memset(a,0,sizeof(a))
    const int INF = 1 << 30;
    typedef long long ll;
    typedef double db;
    template <class T>
    void read(T &x)
    {
        char c;
        bool op = 0;
        while(c = getchar(), c < '0' || c > '9')
            if(c == '-') op = 1;
        x = c - '0';
        while(c = getchar(), c >= '0' && c <= '9')
            x = x * 10 + c - '0';
        if(op) x = -x;
    }
    template <class T>
    void write(T x)
    {
        if(x < 0) putchar('-'), x = -x;
        if(x >= 10) write(x / 10);
        putchar('0' + x % 10);
    }
    struct node
    {
        int fail;
        int vis[26];
        int end;
    }ac[1100001];
    int cnt = 0;
    inline void build(string s)
    {
        int l = s.length();
        int now = 0;
        duke(i,0,l - 1)
        {
            if(ac[now].vis[s[i] - 'a'] == 0)
            ac[now].vis[s[i] - 'a'] = ++cnt;//鏂板缓鑺傜偣
            now = ac[now].vis[s[i] - 'a'];
        }
        ac[now].end ++;
    }
    int n;
    void get_fail()
    {
        queue <int> q;
        duke(i,0,25)
        {
            if(ac[0].vis[i] != 0)
            {
                ac[ac[0].vis[i]].fail = 0;
                q.push(ac[0].vis[i]);
            }
        }
        while(!q.empty()) //bfs
        {
            int u = q.front();
            q.pop();
            duke(i,0,25)
            {
                if(ac[u].vis[i] != 0)
                {
                    ac[ac[u].vis[i]].fail = ac[ac[u].fail].vis[i];
                    q.push(ac[u].vis[i]);
                }
                else
                ac[u].vis[i] = ac[ac[u].fail].vis[i];
            }
        }
    }
    int query(string s)
    {
        int l = s.length();
        int now = 0,ans = 0;
        // cout<<l<<endl;
        duke(i,0,l - 1)
        {
            now = ac[now].vis[s[i] - 'a'];
            for(int t = now;ac[t].end != -1;t = ac[t].fail)
            {
                ans += ac[t].end;
                ac[t].end = -1;
            }
        }
        return ans;
    }
    int main()
    {
        cin>>n;
        string s;
        // cout<<n<<endl;
        for(int i = 1;i <= n;i++)
        {
            cin>>s;
            build(s);
    //        printf("%d
    ",s.length());
        }
        ac[0].fail = 0;
        get_fail();
        cin>>s;
        printf("%d",query(s));
        return 0;
    }
    /*
    2
    a
    aa
    aa
    */
  • 相关阅读:
    设计模式之单例模式(Singleton)
    ASP.Net WebForm温故知新学习笔记:二、ViewState与UpdatePanel探秘
    ASP.Net WebForm温故知新学习笔记:一、aspx与服务器控件探秘
    [学习笔记] $Maximum$ $Minimum$ $identity$
    BZOJ 2159: Crash 的文明世界(组合数学+第二类斯特林数+树形dp)
    BZOJ 3083: 遥远的国度 (树剖+线段树)
    LUOGU P4560 [IOI2014]Wall 砖墙 (线段树)
    牛客网 NOIP赛前集训营-普及组(第四场)C--部分和 (高维前缀和)
    LUOGU P1501 [国家集训队]Tree II (lct)
    LUOGU P3690 【模板】Link Cut Tree (lct)
  • 原文地址:https://www.cnblogs.com/DukeLv/p/9691555.html
Copyright © 2011-2022 走看看