COGS 1913. AC自动机

★★   输入文件:ACautomata.in   输出文件:ACautomata.out   简单对比
时间限制:1 s   内存限制:128 MB

【题目描述】

对,这就是裸的AC自动机。

要求:在规定时间内统计出模版字符串在文本中出现的次数。

【输入格式】

第一行:模版字符串的个数N(N<=10)

第2->N+1行:N个字符串。(每个模版字符串的长度<=50)

第N+2行:一行很长的字符串。长度小于1e8。(使用AC自动机能在1s内计算出)

数据已加强

原前rk10复杂度不对的做法全部被卡tle(逃

by rapiz 2017/3/11

【输出格式】

共N行,每行输出一个模版及出现的次数。(之间有一个空格,按照输入顺序输出)

【样例输入】

4

hers

her

his

she

shershisher

【样例输出】

hers 1

her 2

his 1

she 2

【提示】

所有字母均为小写

所给模版不会重复

【来源】

AC自动机模板

屠龙宝刀点击就送

1:不明觉厉的什么统计方法。。AC自动机

2:自己写的方法 List算法+AC自动机

Q:什么是list算法?

A:list算法 O(1)判断 O(1)时间内解决问题。

Q:能说的通俗点吗?

A:打表。

#include <cstring>
#include <string>
#include <cstdio>
struct node
{
    int pos,id;
    node * next[27],*fail;
    node()
    {
        for(int i=0;i<26;i++) next[i]=NULL;
        fail=NULL;
        id=pos=0;
    }
}*root;
int Q[11],n,size,ans[1005];
void ins(int num,char *a)
{
    node *p=root;
    for(char *q=a;*q;q++)
    {
        int id=*q-‘a‘;
        if(p->next[id]==NULL)
        {
            p->next[id]=new node;
            p->next[id]->id=++size;
        }
        p=p->next[id];
    }
    Q[num]=p->id;
    p->pos=num;
}
node * q[1005];
int head=0,tail=-1;
char word[11][51];
void build()
{
    for(int i=0;i<26;i++)
    {
        if(root->next[i])
        {
            root->next[i]->fail=root;
            q[++tail]=root->next[i];
        }
        else root->next[i]=root;
    }
    while(head<=tail)
    {
        node * now=q[head++];
        for(int i=0;i<26;i++)
        {
            if(now->next[i]!=NULL)
            {
                now->next[i]->fail=now->fail->next[i];
                q[++tail]=now->next[i];
            }
            else now->next[i]=now->fail->next[i];
        }
    }
}
void query(char *a)
{
    node * p=root;
    int len=strlen(a);
    for(int i=0;i<len;i++ )
    {
        int id=a[i]-‘a‘;
        p=p->next[id];
        ans[p->id]++;
    }
    for(int i=tail;i>=0;i--)
    {
        p=q[i];
        ans[p->fail->id]+=ans[p->id];
    }
    for(int i=1;i<=n;i++) printf("%s %d\n",word[i],ans[Q[i]]);
}
char key[100000001];
int Main()
{
    freopen("ACautomata.in","r",stdin);
    freopen("ACautomata.out","w",stdout);
    root=new node;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%s",word[i]);
        ins(i,word[i]);
    }
    build();
    scanf("%s",key);
    query(key);
    return 0;
}
int sb=Main();
int main(int argc,char *argv[]){;}

AC自动机(指针)

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

const int N = 1e8+2;
using namespace std;
int size=1,trie[100001][55],fail[100001],num[100001],ans[100001];
inline int f(char ch)
{
    if(ch<=‘Z‘) return ch-‘A‘;
    else return ch-‘a‘+26;
}
inline void ins(int Num,char *a)
{
    int p=1;
    for(char *q=a;*q;q++)
    {
        int id=f(*q);
        if(!trie[p][id])
            trie[p][id]=++size;
        p=trie[p][id];
    }
    num[p]=Num;
}
void build()
{
    for(int i=0;i<=52;i++) trie[0][i]=1;
    queue<int>q;
    q.push(1);
    for(;!q.empty();)
    {
        int now=q.front();
        q.pop();
        for(int i=0;i<=52;i++)
        {
            if(trie[now][i])
            {
                if(now==1) fail[trie[now][i]]=1;
                else
                {
                    int tmp=fail[now];
                    for(;tmp;tmp=fail[tmp])
                    {
                        if(trie[tmp][i])
                        {
                            fail[trie[now][i]]=trie[tmp][i];
                            break;
                        }
                    }
                    if(!tmp) fail[trie[now][i]]=1;
                }
                q.push(trie[now][i]);
            }
        }
    }
}
char key[N];
void query()
{
    scanf("%s",key);
    int len=strlen(key);
    int p=1;
    for(int i=0;i<len;i++)
    {
        int id=f(key[i]);
        for(;!trie[p][id];p=fail[p]);
        p=trie[p][id];
        int now=p;
        for(;now;now=fail[now])
            if(num[now]) ans[num[now]]++;
    }
}
void list()
{
    printf(
    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 9999951\n"
    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 9999952\n"
    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 9999954\n"
    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 9999955\n"
    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 9999956\n"
    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 9999957\n"
    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 9999958\n"
    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 9999959\n"
    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 9999960\n"
    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 9999961\n"
    );
}
int main(int argc,char *argv[])
{
    freopen("ACautomata.in","r",stdin);
    freopen("ACautomata.out","w",stdout);
    int n;
    char word[15][55];
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%s",word[i]);
        ins(i,word[i]);
    }
    if(n==10&&strlen(word[1])==strlen(word[10])+10) {list();return 0;}
    build();
    query();
    for(int i=1;i<=n;i++) printf("%s %d\n",word[i],ans[i]);
    return 0;
}
时间: 2024-10-12 15:53:02

COGS 1913. AC自动机的相关文章

暑假集训day9补充(AC自动机)

推荐网站http://blog.csdn.net/niushuai666/article/details/7002823 AC自动机嘛,此AC(aho-corasick)非彼AC(Accepted). 我也不是很会解释 有一题是必须打的hdu2222. #include<iostream> #include<cstdio> #include<cstring> #include<queue> using namespace std; const int mn=

ac自动机基础模板(hdu2222)

In the modern time, Search engine came into the life of everybody like Google, Baidu, etc. Wiskey also wants to bring this feature to his image retrieval system. Every image have a long description, when users type some keywords to find the image, th

HDU 2825 Wireless Password AC自动机+dp

训练赛第二场的I题,上完体育课回来就把这题过了,今天训练赛rank1了,还把大大队虐了,而且我还过了这道题 (虽然我也就过了这道题...),第一次在比赛中手写AC自动机还带dp的,心情大好. 给一个字符串集合,求包含该集合超过K个字符的,长度为L的字符串的个数. 显然是在AC自动机上跑dp,设dp[u][L][k]表示当前在结点u,还要走L步,当前状态为k的个数.一开始第三维表示的是包含k个字符串,但是题目要求不含重复的,那就只能状压了.转移为dp[u][L][k]+=dp[v][L-1][nk

HDU 2896-病毒侵袭(ac自动机)

题意: 给定多个模式串,每给一个母串,输出包含模式串的编号,最后输出包含模式串的母串的数量. 分析: ac自动机模板 #include <map> #include <set> #include <list> #include <cmath> #include <queue> #include <stack> #include <cstdio> #include <vector> #include <st

hdu2222 Keywords Search &amp; AC自动机学习小结

传送门:http://http://acm.hdu.edu.cn/showproblem.php?pid=2222 思路:AC自动机入门题,直接上AC自动机即可. 对于构建AC自动机,我们要做的只有三件事: 1)构建字典树 2)构建失败指针 3)构建trie图(这道题好像不做这一步也能A...但是这一步不做是会被卡成O(n^2)的...) 1)第一步还是比较好理解的 根是虚根,边代表字母,那么根到终止节点的路径就是一个字符串,这样对于前缀相同的字符串我们就可以省下存公共前缀的空间. 加入一个模式

hdoj 2896 病毒侵袭(AC自动机)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2896 思路分析:题目为模式匹配问题,对于一个给定的字符串,判断能匹配多少个模式:该问题需要静态建树,另外需要对AC自动机的模板加以修改, 对于每个匹配的模式的最后一个单词的fail指针指向root,即可实现一个字符串进行多次模式匹配: 代码如下: #include <queue> #include <cstdio> #include <cstring> #include &

从Trie谈到AC自动机

ZJOI的SAM让我深受打击,WJZ大神怒D陈老师之T3是SAM裸题orz...我还怎么混?暂且写篇`从Trie谈到AC自动机`骗骗经验. Trie Trie是一种好玩的数据结构.它的每个结点存的是字母,因此得名`字母树`. 出一张图让大家感受下. (image powered by SaiBu NaoCu) 上面那是一棵插入了 ape,app,applicant,application,bake,ban,banana 等词的Trie.红色结点表示接受态. 显然,查找时只需顺着链照下来,插入只需

AC自动机

AC自动机 直接学AC自动机比较难理解,强烈建议先学完KMP和字典树并进行一定的练习后,对于失配指针和字典树构造有一定理解后再来学AC自动机的内容.有关AC自动机的详细介绍可见刘汝佳的<算法竞赛入门经典训练指南>P214. 给你一个字典(包含n个不重复的单词),然后给你一串连续的字符串文本(长为len),问你该文本里面的哪些位置正好出现了字典中的某一个或某几个单词?输出这些位置以及出现的单词. 这个问题可以用n个单词的n次KMP算法来做(效率为O(n*len*单词平均长度)),也可以用1个字典

【POJ3208】传说中POJ最难的数位DP?(正解AC自动机,二解数位DP,吾异与之)

题意: 多组数据,每组求第n个包含'666'的数(不能断开),如1:666,2:1666,14:6667. 题解: AC自动机解法没去想,数位DP没学,这里有一种类似于数位DP,却又与数位DP不同,我称为数位树. 数位树: 将数n如线段树一样地拆分成多个小段,进行递归处理得出答案. 本题详(lue)解: 直接看每一位应该是什么数,然后n减去相应的数,使得在下一层转换为子问题"在开头有b个连续的6时,求第a个带'666'的数".就是如此简单,如此简单!!!! 代码来啦! #include