hdu2222 AC自动机

题意:

题目的意思是给你一些模板串,问你这些模板串在主串中出现的数量。

tag:AC自动机

分析:直接使用AC自动机模板求解, 注意如果不加mark数组会超时, mark数组保证已经统计过的顶点不需要再统计。


#include <algorithm>
#include <cstring>
#include <algorithm>
#include <queue>
#include <cstdio>

using namespace std;
const int N = 500000 + 100;
const int maxn = 1000000 + 100;
const int Root = 0;

struct Trie{
    char data;
    int cnt;      //结点所对应单词的数量
    int fail;      //fail失败指针
    int next[26];
}tree[N];
int tot;

void init(int p, char a) {
    tree[p].data = a;
    tree[p].cnt = 0;
    tree[p].fail = -1;
    memset(tree[p].next, -1, sizeof(tree[p].next));
}

void Insert(char s[]) {
    int p = Root;
    for(int i=0; s[i]; i++) {
        int t = s[i] - 'a';
        if(tree[p].next[t] == -1)  {   //申请内存
            ++tot; init(tot, s[i]);
            tree[p].next[t] = tot;
        }
        p = tree[p].next[t];
    }
    tree[p].cnt++;
}

void get_fail() {
    queue<int> que;
    tree[Root].fail = -1;
    que.push(Root);
    while(!que.empty()) {
        int k = que.front(); que.pop();
        for(int j=0; j<26; j++) {
            int son = tree[k].next[j];
            if(son != -1) {
                if(k == Root) tree[son].fail = Root;
                else {
                    int t = tree[k].fail;
                    while(t!=-1 && tree[t].next[j]==-1) t = tree[t].fail;
                    if(t == -1) tree[son].fail = Root;
                    else tree[son].fail = tree[t].next[j];
                }
                que.push(son);
            }
        }
    }
}

bool mark[N];
int query(char s[]) {
    int p = Root, ans = 0;
    memset(mark, 0, sizeof(mark));
    for(int i=0; s[i]; i++) {
        mark[p] = 1;
        int t = s[i] - 'a';
        while(tree[p].next[t]==-1 && p) p = tree[p].fail;
        p = tree[p].next[t];
        if(p == -1) { p = Root; continue; };
        int j = p;
        if(!mark[j])
        while(j) {
            ans += tree[j].cnt;
            tree[j].cnt = 0;
            j = tree[j].fail;
        }
    }
    return ans;
}

char str[100], s[maxn];
int main() {
    int T; scanf("%d", &T);
    while(T--) {
        tot = 0;
        init(Root, -1);
        int n; scanf("%d", &n);
        while(n--) {
            scanf("%s", str);
            Insert(str);
        }
        get_fail();
        scanf("%s", s);
        int ans = query(s);
        printf("%d\n", ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值