P3808 AC自动机(简单版)
P3808 AC自动机(简单版)
题目描述
给定
两个模式串不同当且仅当他们编号不同。
输入格式
第一行是一个整数,表示模式串的个数
第
最后一行是一个字符串,表示文本串
输出格式
输出一行一个整数表示答案。
------------------------------------------------------------------------------------
rt,我们需要维护一个AC自动机。
首先我们需要对所以模式串建立一颗Trie,然后将这个文本串放入这颗Trie中匹配
剩下的细节先咕着,因为上课了
code:
#include <bits/stdc++.h> using namespace std; const int N=1e6+5; int cnt,tot,n,ans; char c[N],s[N]; struct Tree{ int son[26],id,fail,num; }t[N]; void init() { for(int i=1;i<=cnt;i++)t[i]=Tree{{0},0,1,0}; cnt=1,ans=0; } void add(char c[])//常规Trie插入 { int x=1,len=strlen(c); for(int i=0;i<=len-1;i++) { int to=c[i]-'a'; if(t[x].son[to]) { t[x].son[to]; } else { t[x].son[to]=++cnt; } x=t[x].son[to]; } t[x].num++; return ; } void getfail() { queue<int> q; for(int i=0;i<=25;i++) { int to=t[1].son[i]; if(!to)continue; q.push(to); t[to].fail=1; } while(!q.empty()) { int u=q.front(); q.pop(); for(int i=0;i<26;i++) { int to=t[u].son[i]; if(to) { t[to].fail=t[t[u].fail].son[i];//fail:指向to的后缀(即[root->fail]这条路径上的字符串是[toot->to]的一个后缀) //显然,fail在Trie上的深度要比to浅(前缀的长度肯定小于等于原串) q.push(to); } else { t[u].son[i]=t[t[u].fail].son[i];//如果这个点没有字符,为了方便查询,将这个点连到后缀的儿子上方便匹配 } } } return ; } void query(char s[]) { int len=strlen(s); int x=1; for(int i=0;i<=len-1;i++) { int ch=s[i]-'a'; x=t[x].son[ch]; for(int j=x;1^j && ~t[j].num;j=t[j].fail)//查询,遍历树上所有的ch的fail指针,匹配对应字符串 { ans+=t[j].num; t[j].num=-1; } } } int main() { //freopen("ac.in","r",stdin); //freopen("ac.out","w",stdout); cin>>n; init(); for(int i=1;i<=n;i++) { scanf("%s",c); add(c); } getfail(); scanf("%s",s); query(s); printf("%d\n",ans); return 0; }