AC自动机模板(luoguP3808 【模板】AC自动机(简单版))

题目背景

这是一道简单的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;

%:pragma GCC optimize(2)
;
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <queue>

using namespace std;

const int N = 1e6 + 10;

int cnt, nxt[N][30], fail[N], tot[N], ans, n;

char s[N];

queue<int> q;

void insert() {
    scanf("%s", s);
    int x = 0;
    for(int i = 0 ; s[i] ; ++ i) {
        int c = s[i] - 'a';
        if(!nxt[x][c]) nxt[x][c] = ++ cnt;
        x = nxt[x][c];
    }
    ++ tot[x];
}

void bfs() {
    for(int i = 0 ; i < 26 ; ++ i) {
        if(nxt[0][i]) {
            fail[nxt[0][i]] = 0;
            q.push(nxt[0][i]);
        }
    }
    while(q.size()) {
        int u = q.front(); q.pop();
        for(int i = 0 ; i < 26 ; ++ i) {
            int v = nxt[u][i];
            if(!v) nxt[u][i] = nxt[fail[u]][i];
            else {
                fail[v] = nxt[fail[u]][i];
                q.push(v);
            }
        }
    }
}

void sol() {
   scanf("%s", s);
   int u = 1;
   for(int i = 0 ; s[i] ; ++ i) {
        u = nxt[u][s[i] - 'a'];
        int v = u;
        while(v && ~tot[v]) {
            ans += tot[v];
            tot[v] = -1;
            v = fail[v];
        }
   }
}

int main() {
    scanf("%d", &n);
    for(int i = 1 ; i <= n ; ++ i) {
        insert();
    }
    bfs();
    sol();
    printf("%d\n", ans);
    return 0;
}

  

posted @ 2017-10-23 11:28  KingSann  阅读(180)  评论(0编辑  收藏  举报