「模板」AC自动机(ACAM)

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
const int MAXN=160,MAXM=11000,MAXL=1000010;
char str[MAXN][80],p[MAXL];
int n;
class ACAM
{
    public:
        void Init(void)
        {
            tot=0;
            memset(cnt,0,sizeof cnt);
            memset(s,0,sizeof s);
        }
        void Insert(char *str,int k)
        {
            int x=0;
            for(int i=0,t;str[i];++i)
            {
                if(!s[x].c[t=num(str[i])])
                    s[x].c[t]=++tot;
                x=s[x].c[t];
            }
            s[x].index=k;
        }
        void GetFail(void)
        {
            queue<int> q;
            for(int i=1,t;i<=26;++i)
                if(t=s[0].c[i])
                {
                    s[t].fail=0;
                    q.push(t);
                }
            while(!q.empty())
            {
                int x=q.front();
                q.pop();
                for(int i=1,t,f;i<=26;++i)
                    if(t=s[x].c[i])
                    {
                        f=s[t].fail=s[s[x].fail].c[i];
                        s[t].lst=s[f].index?f:s[f].lst;
                        q.push(t);
                    }
                    else
                        s[x].c[i]=s[s[x].fail].c[i];
            }
        }
        void Search(char *p)
        {
            int x=0,ans=0;
            for(int i=0;p[i];++i)
            {
                if(s[x=s[x].c[num(p[i])]].index)
                    ++cnt[s[x].index];
                for(int j=s[x].lst;j;j=s[j].lst)
                    ++cnt[s[j].index];
            }
            for(int i=1;i<=n;++i)
                ans=max(ans,cnt[i]);
            printf("%d\n",ans);
            for(int i=1;i<=n;++i)
                if(cnt[i]==ans)
                    printf("%s\n",str[i]);
        }
    private:
        int tot,cnt[MAXN];
        struct node
        {
            int index,fail,lst,c[27];
        }s[MAXM];
        int num(char c)
        {
            return c-‘a‘+1;
        }
}AC;
int main(int argc,char *argv[])
{
    while(scanf("%d",&n) && n)
    {
        AC.Init();
        for(int i=1;i<=n;++i)
        {
            scanf("%s",str[i]);
            AC.Insert(str[i],i);
        }
        AC.GetFail();
        scanf("%s",p);
        AC.Search(p);
    }
    return 0;
}
时间: 2024-08-01 20:16:38

「模板」AC自动机(ACAM)的相关文章

LG5357 「模板」AC自动机(二次加强版) AC自动机+fail树

问题描述 LG5357 题解 不是fail树的AC自动机复杂度是假的. 把AC自动机搞出来,建立Trie树,树上爆搜一遍就好了. \(\mathrm{Code}\) #include<bits/stdc++.h> using namespace std; template <typename Tp> void read(Tp &x){ x=0;char ch=1;int fh; while(ch!='-'&&(ch>'9'||ch<'0')) c

luogu P3808 【模板】AC自动机(简单版)

二次联通门 : luogu P3808 [模板]AC自动机(简单版) /* luogu P3808 [模板]AC自动机(简单版) 手速越来越快了 10分钟一个AC自动机 一遍过编译 + 一边AC 感觉不错 我也就做做板子题了.. */ #include <iostream> #include <cstring> #include <cstdio> #include <queue> #define Max 1000009 void read (int &

【模板】AC自动机

来自洛谷的两道AC自动机模板题: [模板]AC自动机(简单版) 题目背景 这是一道简单的AC自动机模板题. 用于检测正确性以及算法常数. 为了防止卡OJ,在保证正确的基础上只有两组数据,请不要恶意提交. 管理员提示:本题数据内有重复的单词,且重复单词应该计算多次,请各位注意 题目描述 给定n个模式串和1个文本串,求有多少个模式串在文本串里出现过. 输入输出格式 输入格式: 第一行一个n,表示模式串个数: 下面n行每行一个模式串: 下面一行一个文本串. 输出格式: 一个数表示答案 输入输出样例 输

「模板」 FHQ_Treap

「模板」 FHQ_Treap <题目链接> 我也是偶然发现我还没发过FHQ_Treap的板子. 那就发一波吧. 这个速度实在不算快,但是不用旋转,并且好写. 更重要的是,Splay 可以做的事情它都可以做!比如区间操作,以及LCT相关- 而且它还可以可持久化!(虽然目前还没有学) Capella 认为,不涉及区间操作时,用快一些的平衡树(SBT/Treap/替罪羊...)较好,涉及区间操作而又不想写大量代码的话,FHQ_Treap 不失为一种极好的选择. 下一篇写 FHQ_Treap 的区间操

「模板」 割点

「模板」 割点 <题目链接> 不会点双导致的 APIO 完挂. 本应该联赛前学的东西,不及时学,就只有等到变回联赛选手后再学了吧. 以及,以后放弃链式前向星,存图一律指针邻接表. #include <algorithm> #include <cstdio> using std::min; const int MAXN=100010; bool cut[MAXN]; int n,m,DFN_num,ans,DFN[MAXN],low[MAXN]; struct Edge

「模板」 树套树

「模板」 树套树 <题目链接> 线段树套 SBT. 有生以来写过的最长代码. 虽然能过,但我删除 SBT 点的时候没回收内存!写了就 RE! 先放上来吧,回收内存调出来了再修改qwq. #include <algorithm> #include <climits> #include <cstdio> using std::max; using std::min; const int MAXN=50010; int n,m; class SegmentTree

「模板」 线段树——区间乘 &amp;&amp; 区间加 &amp;&amp; 区间求和

「模板」 线段树--区间乘 && 区间加 && 区间求和 <题目链接> 原来的代码太恶心了,重贴一遍. #include <cstdio> int n,m; long long p; class SegmentTree { private: struct Node { int l,r; long long v,mul,add; Node *c[2]; Node(int l,int r):l(l),r(r),mul(1LL),add(0LL) { c[

【学时总结&amp;模板时间】◆学时&#183;10 &amp; 模板&#183;3◆ AC自动机

◇学时·10 & 模板·3◇ AC自动机 跟着高中上课……讲AC自动机的扩展运用.然而连KMP.trie字典树都不怎么会用的我一脸懵逼<(_ _)> 花一上午自学了一下AC自动机 QwQ ? Trie树 字典树的一种(听说还有其他字典树,不清楚).每个节点代表一个字母,根节点相当于超级源点,根节点不表示字母.Trie树最大的特点是从根节点出发,沿着树边向下走,走过的节点会形成一个字符串.而一些节点是某一个单词的结尾,对于这种节点,我们一般会给它做一个标记(ovr). ? 构建Trie树

【题解】P3796【模板】AC自动机(加强版)

[题解]P3796 [模板]AC自动机(加强版) 记录当前\(cnt\)是第几个"星".记录第几个串是对应着第几个星. 这里补充一点对于\(AC\)自动机的理解.可能一直有个问题我没有想明白,就是打标记的点只有一个,然而匹配时,假若一个分支包括了另一个不同的分支该怎么办.实际上,我们可以在匹配的时候使用\(fail\)数组进行类似链式前向星的遍历,从而遍历到那个打标记的地方.那么问题来了,怎么保证链式前向星会遍历到那个打了标记的节点呢?答案就在\(gen\_fail\)的玄机里.\(g