洛谷P3808 【模板】AC自动机(简单版)

题目描述

给定n个模式串和1个文本串,求有多少个模式串在文本串里出现过。

输入输出格式

输入格式:

第一行一个n,表示模式串个数;

下面n行每行一个模式串;

下面一行一个文本串。

输出格式:

一个数表示答案

题解:AC自动机裸题

#include <bits/stdc++.h>
using namespace std;
int const N = 1000005;
int const M = 1000005;
struct Node{
	Node *next[26];
	Node *fail;
	int cnt;
	Node(){
		memset(next,NULL,sizeof(next));
		fail = NULL;
		cnt = 0;
	}
}*q[M],*root;
void Insert(char *s){
	int n = strlen(s);
	Node *now = root;
	for(int i=0;i<n;i++){
		int to = s[i] - 'a';
		if(now->next[to] == NULL)	now->next[to] = new Node();
		now = now->next[to];
	}
	now->cnt++;
}
void Get_Fail(){
	int head = 0,tail = 0;
	q[head++] = root;
	root->fail = NULL;
	while(head != tail){
		Node *tmp = q[tail++];
		Node *p;
		for(int i=0;i<26;i++){
			if(tmp->next[i] == NULL)	continue;
			if(tmp == root)	tmp->next[i]->fail = root;
			else{
				p = tmp->fail;
				while(p){
					if(p->next[i]){
						tmp->next[i]->fail = p->next[i];
						break;
					}
					p = p->fail;
				}
				if(p == NULL)	tmp->next[i]->fail = root;
			}
			q[head++] = tmp->next[i];
		}
	}
}
int Match(char *str){
	int len = strlen(str);
	Node *p = root;	
	int ans = 0;
	for(int i=0;i<len;i++){
		int to = str[i] - 'a';
		while(p && p->next[to] == NULL)	p = p->fail;
		if(p)	p = p->next[to];
		else p = root;
		Node *tmp = p;
		while(tmp != root){
			if(tmp->cnt>=0){  //标记是否访问过
				ans += tmp->cnt;
				tmp->cnt = -1;
			}else break;
			tmp = tmp->fail;
		}
	}
	return ans;
}
int main(){
		int n;
		scanf("%d",&n);
		root = new Node();
		while(n--){
			char s[55];
			scanf(" %s",s);
			Insert(s);
		}
		char str[N];		
		scanf(" %s",str);
		Get_Fail();
		printf("%d\n",Match(str));
	return 0;
}

 

posted @ 2019-02-06 23:01  月光下の魔术师  阅读(10)  评论(0)    收藏  举报