bzoj3172 Ac自动机

根据fail树的性质 我们在建树的时候每建一个串就将他路径上的点全部加1表示这个串的后缀又出现了一次 然后从下到上把sum加起来就可以得到答案了

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int size=26,M=1000005;
char c[M];
int w[255],n;
struct node{
    int sum,fail[M],a[M][27],ans[M];
    int id(char s){return s-‘a‘+1;}
    void insert(char s[],int &x){
        int k=0,L=strlen(s);
        for(int i=0;i<L;i++){
            int now=id(s[i]);
            if(!a[k][now]) a[k][now]=++sum;
            ans[a[k][now]]++;
            k=a[k][now];
        }
        x=k;
    }
    int q[M],head,tail;
    void Ac_boy(){
        for(int i=1;i<=size;i++){
            int now=a[0][i];
            if(now) q[tail++]=now;
        }
        while(head!=tail){
            int x=q[head++];
            for(int i=1;i<=size;i++){
                int now=a[x][i];
                if(!now){a[x][i]=a[fail[x]][i];continue;}
                q[tail++]=now;
                fail[now]=a[fail[x]][i];
            }
        }
    }
    void work(){
        for(int i=tail-1;i>=0;i--) ans[fail[q[i]]]+=ans[q[i]];
        for(int i=1;i<=n;i++) printf("%d\n",ans[w[i]]);
    }
}node;
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%s",c),node.insert(c,w[i]);
    node.Ac_boy(); node.work();
    return 0;
}

时间: 2024-08-23 03:12:33

bzoj3172 Ac自动机的相关文章

【bzoj3172】: [Tjoi2013]单词 字符串-AC自动机

[bzoj3172]: [Tjoi2013]单词 先用所有单词构造一个AC自动机 题目要求的是每个单词在这个AC自动机里匹配到的次数 每次insert一个单词的时候把路径上的cnt++ 那么点p->cnt就是以root到p这条路径为前缀的单词的个数 如果p->fail指向了点q,那么就会对q点产生p->cnt的贡献(root到q一定为root到p的后缀) 最后递推统计完所有fail的贡献,找到关键点输出就可以了 1 /* http://www.cnblogs.com/karl07/ */

【BZOJ3172】单词(AC自动机)

[BZOJ3172]单词(AC自动机) 题面 Description 某人读论文,一篇论文是由许多单词组成.但他发现一个单词会在论文中出现很多次,现在想知道每个单词分别在论文中出现多少次. Input 第一个一个整数N,表示有多少个单词,接下来N行每行一个单词.每个单词由小写字母组成,N<=200,单词长度不超过10^6 Output 输出N个整数,第i行的数字表示第i个单词在文章中出现了多少次. Sample Input 3 a aa aaa Sample Output 6 3 1 题解 yy

【BZOJ3172】【Tjoi2013】单词 AC自动机模板题

转载请注明出处:http://blog.csdn.net/vmurder/article/details/42711351 其实我就是觉得原创的访问量比未授权盗版多有点不爽233... 题解:水爆了,直接AC自动机瞎写就行. 坑:--时隔一个半月的感动AC,竟然是因为这道题可以有重复单词233. 代码: #include <queue> #include <cstdio> #include <cstring> #include <iostream> #inc

[BZOJ3172 ][Tjoi2013]单词(AC自动机)

Description 不稳定的传送门 某人读论文,一篇论文是由许多单词组成.但他发现一个单词会在论文中出现很多次,现在想知道每个单词分别在论文中出现多少次.单词个数<=200,单词总长度<=10^6 Solution AC自动机的入门题,将所有单词建一颗字典树,并构造fail树 然后随便统计一下数量就可以了 Code #include <cstdio> #include <algorithm> #include <cstring> #define R re

暑假集训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)第一步还是比较好理解的 根是虚根,边代表字母,那么根到终止节点的路径就是一个字符串,这样对于前缀相同的字符串我们就可以省下存公共前缀的空间. 加入一个模式