HDU

原题地址HDU - 3065

题意:给出N个模式串(在ascii范围内(128)),再给你一个文本串 (2 e6 以内),输出存在的模式串以及出现次数 (计数可以重叠)

思路:AC自动机啦,我们要会用last优化后ac-atomaton

#include<bits/stdc++.h>
const int M=2e6+10;
const int N=100000+5;
using namespace std;

queue<int> q;
int res[N];//记录结果
struct AC_Automata{
    int tire[N][128];//字典树
    int val[N];//字符串结尾标记
    int fail[N];//失配指针
    int last[N];//last[i]=j表j节点表示的单词是i节点单词的后缀,且j节点是单词节点
    int tot;//编号

    void init(){//初始化0号点
        tot=1;
        val[0]=fail[0]=last[0]=0;
        memset(tire[0],0,sizeof(tire[0]));
    }

    void insert(char *s,int v){//构造trie与val数组,v需非0,表示一个单词节点
        int len=strlen(s);
        int root=0;
        for(int i=0;i<len;i++){
            int id=s[i];
            if(tire[root][id]==0){
                tire[root][id]=tot;
                memset(tire[tot],0,sizeof(tire[tot]));
                val[tot++]=0;
            }
            root=tire[root][id];
        }
        val[root]=v;
    }

    void build(){//构造fail与last
        while(!q.empty()) q.pop();
        last[0]=fail[0]=0;
        for(int i=0;i<128;i++){
            int root=tire[0][i];
            if(root!=0){
                fail[root]=0;
                last[root]=0;
                q.push(root);
            }
        }

        while(!q.empty()){//bfs求fail
            int k=q.front();
            q.pop();
            for(int i=0;i<128;i++){
                int u=tire[k][i];
                if(u==0)
                    continue;
                q.push(u);

                int v=fail[k];
                while(v && tire[v][i]==0)
                    v=fail[v];
                fail[u]=tire[v][i];
                last[u]=val[fail[u]]?fail[u]:last[fail[u]];
            }
        }
    }

    void print(int i){//递归打印与结点i后缀相同的前缀节点编号
        if(val[i]){
            res[val[i]]++;
            print(last[i]);
        }
    }

    void query(char *s){//匹配
        int len=strlen(s);
        int j=0;
        for(int i=0;i<len;i++){
            int id=s[i];
            while(j && tire[j][id]==0)
                j=fail[j];
            j=tire[j][id];
            if(val[j])
                print(j);
            else if(last[j])
                print(last[j]);
        }
    }
}ac;
char P[1005][100];
char T[M];
int main(){
    int n;
    while(scanf("%d",&n)!=EOF&&n){
        memset(res,0,sizeof(res));
        ac.init();

        for(int i=1;i<=n;i++){
            scanf("%s",P[i]);
            ac.insert(P[i],i);
        }
        ac.build();

        scanf("%s",T);
        ac.query(T);
        for(int i=1;i<=n;i++)
            if(res[i])
                printf("%s: %d
",P[i],res[i]);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/Tianwell/p/11377117.html