[模板]AC自动机

https://blog.csdn.net/creatorx/article/details/71100840
AC自动机就是一直跳fail边,然后找到整个要匹配的串就行了。
fail边:大概就是指向以当前节点表示的字符 为最后一个字符的 最长当前字符串的 后缀字符串的 最后一个节点(摘自上面的博客并断句
代码:luogu3808

#include <iostream>
#include <cstdio>
#include <queue>
#include <cstring>
using namespace std;
int n;
const int N=500010;
struct ACZDJ {
    int tr[N][26],fail[N],val[N],cnt;
    void insert(char *s) {
        int len=strlen(s),p=0;
        for(int i=0; i<len; i++) {
            if(!tr[p][s[i]-'a']) tr[p][s[i]-'a']=++cnt;
            p=tr[p][s[i]-'a'];
        }
        val[p]++;
    }
    void build() {
        queue<int>q;
        for(int i=0; i<26; i++)
            if(tr[0][i]) q.push(tr[0][i]),fail[tr[0][i]]=0;
        while(!q.empty()) {
            int u=q.front();
            q.pop();
            for(int i=0; i<26; i++) {
                if(tr[u][i]) q.push(tr[u][i]),fail[tr[u][i]]=tr[fail[u]][i];
                else tr[u][i]=tr[fail[u]][i];
            }
        }
    }
    int query(char *s) {
        int len=strlen(s),p=0,ans=0;
        for(int i=0; i<len; i++) {
            int v=s[i]-'a';
            p=tr[p][v];
            for(int j=p; ~val[j]&&j; j=fail[j]) {
                ans+=val[j];
                val[j]=-1;
            }
        }
        return ans;
    }
} AC;
char s[2000005];
int main() {
    scanf("%d",&n);
    while(n--) {
        scanf("%s",s);
        AC.insert(s);
    }
    AC.build();
    scanf("%s",s);
    cout<<AC.query(s);
}

猜你喜欢

转载自www.cnblogs.com/sdfzhsz/p/9314832.html