HDU2222-AC自动机

这题直接用AC自动机模板再加上这个结点已经被访问过了该结点就不需要再使用因为查找的字符串只有一个,所以直接把这个结点对应的值重置为0,如果有多个用标记数组标记一下有没有用过即可
题目链接

#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
#include<iostream>
using namespace std;
#define mes(s) memset(s,0,sizeof(s))
const int mx = 1e6+5;
char s[mx];

struct trie{
    int ch[mx][26];
    int v[mx],f[mx],last[mx];
    int sz;
    void init(){mes(ch[0]),sz = 1,mes(v),mes(f),mes(last);}
    int idx(char c){return c-'a';}
    void insert(char *s){
        int len = strlen(s);
        int u = 0;
        for(int i = 0; i < len; i++){
            int d = idx(s[i]);
            if(!ch[u][d]){
                mes(ch[sz]);
                ch[u][d] = sz++;
            }
            u = ch[u][d];
        }
        v[u]++;
    }
    void getfail(){
        queue<int>q;
        for(int d = 0; d < 26; d++){
            if(!ch[0][d]){
                ch[0][d] = 0;
                continue;
            }
            int ret = ch[0][d];
            last[ret] = f[ret] = 0;
            q.push(ret);
        }
        while(!q.empty()){
            int u = q.front();
            q.pop();
            for(int d = 0; d < 26; d++){
                if(!ch[u][d]){
                    ch[u][d] = ch[f[u]][d];
                    continue;
                }
                int ret = ch[u][d];
                f[ret] = ch[f[u]][d];
                last[ret] = v[f[ret]]?f[ret]:last[f[ret]];
                q.push(ret);
            }
        } 
    }
    int find(char *s){
        int ans = 0,u = 0;
        int len = strlen(s);
        for(int i = 0; i < len; i++){
            int d = idx(s[i]);
            int ret = ch[u][d];
            while(ret){
                ans += v[ret];
                v[ret] = 0;
                ret = last[ret];
            }
            u = ch[u][d];
        }
        return ans;
    }
}word; 
int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        int n;
        scanf("%d",&n);
        word.init();
        for(int i = 1; i <= n; i++){
            scanf("%s",s);
            word.insert(s);
        }
        word.getfail();
        scanf("%s",s);
        printf("%d\n",word.find(s));
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值