HDU 3065 病毒侵袭持续中 (AC自动机)

时间:2021-01-04 00:19:02

题目地址:HDU 3065
裸的AC自动机。由于AC自动机的指针是不断回溯的,所以对于AA在AAA中算两次的问题完全不用担心,当在第二个A中+1后,指针会再次回溯到A上,然后当到第三个A的时候,会再记录一次。
代码如下:

#include <iostream>
#include <string.h>
#include <math.h>
#include <queue>
#include <algorithm>
#include <stdlib.h>
#include <map>
#include <set>
#include <stdio.h>
#include <string>
#include <time.h>
using namespace std;
#define LL long long
#define pi acos(-1.0)
#pragma comment(linker, "/STACK:1024000000")
const int mod=9901;
const int INF=0x3f3f3f3f;
const double eqs=1e-9;
const int MAXN=1000000+300;
char s[2000000], st[1100][60];
struct Trie
{
int next[50010][130], fail[50010], id[50010], ha[1100];
int root, L;
int newnode()
{
for(int i=0;i<128;i++){
next[L][i]=-1;
}
id[L++]=0;
return L-1;
}
void init()
{
L=0;
root=newnode();
}
void Insert(char s[], int f)
{
int len=strlen(s);
int now=root;
for(int i=0;i<len;i++){
if(next[now][s[i]]==-1) next[now][s[i]]=newnode();
now=next[now][s[i]];
}
id[now]=f;
}
void Build()
{
queue<int>q;
fail[root]=root;
for(int i=0;i<128;i++){
int v=next[root][i];
if(v==-1) next[root][i]=root;
else {
fail[v]=root;
q.push(v);
}
}
while(!q.empty()){
int u=q.front();
q.pop();
for(int i=0;i<128;i++){
int v=next[u][i];
if(v==-1){
next[u][i]=next[fail[u]][i];
}
else{
fail[v]=next[fail[u]][i];
q.push(v);
}
}
}
}
void Query(char s[], int n)
{
memset(ha,0,sizeof(ha));
int ans=0, now=root;
int len=strlen(s);
for(int i=0;i<len;i++){
now=next[now][s[i]];
int tmp=now;
while(tmp!=root){
if(id[tmp]){
ha[id[tmp]]++;
}
tmp=fail[tmp];
}
}
for(int i=1;i<=n;i++){
if(ha[i]){
printf("%s: %d\n",st[i],ha[i]);
}
}
}
}ac;
int main()
{
int n, m, i, sum;
while(scanf("%d",&n)!=EOF){
ac.init();
for(i=1;i<=n;i++){
scanf("%s",st[i]);
ac.Insert(st[i],i);
}
ac.Build();
scanf("%s",s);
ac.Query(s,n);
}
return 0;
}