[模板] 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\n",s.length());
    }
    ac[0].fail = 0;
    get_fail();
    cin>>s;
    printf("%d",query(s));
    return 0;
}
/*
2
a
aa
aa
*/

猜你喜欢

转载自www.cnblogs.com/DukeLv/p/9691555.html