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

题目地址: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;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值