【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

题解

yyb因为调这道题而死亡

在重复一下题目的意思把。。。
看不见文章对不读,,
那是因为文章就是所有单词组成的
然后你就可以yy所有单词中间有一个空格之类的东西

很明显的AC自动机,
然后,我们
每次把每个单词带进去匹配一下
暴跳fail指针
美滋滋的收获90分

0分是空间玩炸了。。。

暴跳fail指针是可以被卡炸的。。。
所以,我们就不暴跳了呀
每次要跳的时候就在这个点这里打一个标记
所有标记打完之后
我们就从底下往上一层层跳(记一下bfs序倒着跳)
每次就只跳一层,然后标记丢到上面去
这样就可以一起跳啦

然后美滋滋的 AC啦

对了,
这题还有一点
就是会有重复的单词。。。
所以要记录一下每个单词和哪个单词是一样的(不是并查集)

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define MAX 1100000
struct Node
{
    int vis[26];
    int fail,ff;
    int id,sum;
}t[MAX];
int tot,lid[500];
int ans[500];
int n,q[MAX],tp;
char ch[MAX],ss[MAX];
void Insert(int id,char *s)
{
    int gg=strlen(s);
    int now=0;
    for(int i=0;i<gg;++i)
    {
        if(!t[now].vis[s[i]-'a'])
            t[now].vis[s[i]-'a']=++tot;
        t[t[now].vis[s[i]-'a']].ff=now;
        now=t[now].vis[s[i]-'a'];
    }
    if(!t[now].id)t[now].id=id,lid[id]=id;
    else lid[id]=t[now].id;
}
queue<int> Q;
void GetFail()
{
    for(int i=0;i<26;++i)
        if(t[0].vis[i])
            Q.push(q[++tp]=t[0].vis[i]);
    while(!Q.empty())
    {
        int u=Q.front();Q.pop();
        for(int i=0;i<26;++i)
        {
            if(t[u].vis[i])
                t[t[u].vis[i]].fail=t[t[u].fail].vis[i],Q.push(q[++tp]=t[u].vis[i]);
            else
                t[u].vis[i]=t[t[u].fail].vis[i];
        }
    }
}
int l=0;
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;++i)
    {
        scanf("%s",ch);
        Insert(i,ch);
        int len=strlen(ch);
        for(int j=0;j<len;++j)
            ss[l++]=ch[j];
        ss[l++]='#';
    }
    GetFail();
    int now=0;
    for(int j=0;j<l;++j)
    {
        if(ss[j]=='#')now=0;
        else now=t[now].vis[ss[j]-'a'];
        t[now].sum++;
    }
    for(int i=tp;i;i--)
    {
        ans[t[q[i]].id]+=t[q[i]].sum;
        t[t[q[i]].fail].sum+=t[q[i]].sum;
    }
    for(int i=1;i<=n;++i)printf("%d\n",ans[lid[i]]);
    return 0;
}

原文地址:https://www.cnblogs.com/cjyyb/p/8251584.html

时间: 2024-11-05 17:30:01

【BZOJ3172】单词(AC自动机)的相关文章

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

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

BZOJ 3172: [Tjoi2013]单词 [AC自动机 Fail树]

3172: [Tjoi2013]单词 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 3198  Solved: 1532[Submit][Status][Discuss] Description 某人读论文,一篇论文是由许多单词组成.但他发现一个单词会在论文中出现很多次,现在想知道每个单词分别在论文中出现多少次. Input 第一个一个整数N,表示有多少个单词,接下来N行每行一个单词.每个单词由小写字母组成,N<=200,单词长度不超过10^6

【BZOJ-3172】单词 AC自动机

3172: [Tjoi2013]单词 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 2567  Solved: 1200[Submit][Status][Discuss] Description 某人读论文,一篇论文是由许多单词组成.但他发现一个单词会在论文中出现很多次,现在想知道每个单词分别在论文中出现多少次. Input 第一个一个整数N,表示有多少个单词,接下来N行每行一个单词.每个单词由小写字母组成,N<=200,单词长度不超过10^6

[bzoj3172][Tjoi2013]单词——AC自动机

题目大意: 某人读论文,一篇论文是由许多单词组成.但他发现一个单词会在论文中出现很多次,现在想知道每个单词分别在论文中出现多少次. 思路: 第i个单词在整个文章中出现了多少次即i串的结尾可以被多少个串的节点给跳到. 于是吧fail看成每个节点唯一的父亲,每个节点的权值为有多少个单词的前缀经过了它,然后直接统计子树内的权值和即可. #include<bits/stdc++.h> #define REP(i,a,b) for(int i=a,i##_end_=b;i<=i##_end_;++

luogu_3966【题解】单词 AC自动机

题面:https://www.luogu.org/problemnew/show/P3966 大意:小张最近在忙毕设,所以一直在读论文.一篇论文是由许多单词组成但小张发现一个单词会在论文中出现很多次,他想知道每个单词分别在论文中出现了多少次. 这次没有文本串. 用了个奇妙的方法. a[x] 表示第x个串结尾的位置. 在bfs搜索求fail的时候手写,将所有的点都保存下来了. num(x)则为经过这个点x的个数. 自然num(fail(x))+=num(x). 所有经过x的串都能经过fail(x)

BZOJ 3172: [Tjoi2013]单词 AC自动机

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

【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 ][Tjoi2013]单词(AC自动机)

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

跳跃表,字典树(单词查找树,Trie树),后缀树,KMP算法,AC 自动机相关算法原理详细汇总

第一部分:跳跃表 本文将总结一种数据结构:跳跃表.前半部分跳跃表性质和操作的介绍直接摘自<让算法的效率跳起来--浅谈"跳跃表"的相关操作及其应用>上海市华东师范大学第二附属中学 魏冉.之后将附上跳跃表的源代码,以及本人对其的了解.难免有错误之处,希望指正,共同进步.谢谢. 跳跃表(Skip List)是1987年才诞生的一种崭新的数据结构,它在进行查找.插入.删除等操作时的期望时间复杂度均为O(logn),有着近乎替代平衡树的本领.而且最重要的一点,就是它的编程复杂度较同类