bzoj 3172 AC自动机

代码:

//建好AC自动机后就是fail的转移了,数量是从底向上转移的所以用一个队列记录下来节点顺序然后转移val数组即可。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int MAXN=1000009;
int node[MAXN][30],f[MAXN],val[MAXN],tr[209],sz,qq[MAXN];
char s[MAXN];
int n;
void init()
{
    sz=0;
    memset(node[0],0,sizeof(node[0]));
    f[0]=val[0]=0;
}
void insert(char *s,int nu)
{
    int len=strlen(s),rt=0;
    for(int i=0;i<len;i++){
        int id=s[i]-‘a‘;
        if(!node[rt][id]){
            node[rt][id]=++sz;
            memset(node[sz],0,sizeof(node[sz]));
            val[sz]=0;
        }
        rt=node[rt][id];
        val[rt]++;
    }
    tr[nu]=rt;
}
void get_fail()
{
    queue<int>q;
    int top=0;
    for(int i=0;i<26;i++){
        int u=node[0][i];
        if(u) { q.push(u);f[u]=0; }
    }
    while(!q.empty()){
        int rt=q.front();q.pop();qq[++top]=rt;
        for(int i=0;i<26;i++){
            int u=node[rt][i];
            if(!u){
                node[rt][i]=node[f[rt]][i];
                continue;
            }
            q.push(u);
            f[u]=node[f[rt]][i];
        }
    }
    for(int i=top;i>=1;i--) val[f[qq[i]]]+=val[qq[i]];
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%s",s);
        insert(s,i);
    }
    get_fail();
    for(int i=1;i<=n;i++)
        printf("%d\n",val[tr[i]]);
    return 0;
}
时间: 2024-10-12 05:31:21

bzoj 3172 AC自动机的相关文章

bzoj 2434 ac自动机

ac自动机中,如果以trie中的节点为节点,(fail[i],i)为边,可以建立一颗树,该树有如下特点:“节点u是节点v的祖先 当且仅当 u代表的字符串是v代表的字符串的一个后缀”.(u代表的字符串是由根节点到u路径上所有的边代表的字符顺次组合成的,我们记作str(u)). 本题中的每一个P都对应trie中的一个节点,所以本题就是求str(b)中有多少个str(a)子串: 如果len(str(b))<len(str(a)),则为0 如果len(str(b))==len(str(a)),则判断a和

bzoj 1030 AC自动机+dp

代码: //先把给的单词建AC自动机并且转移fail,然后d[i][j]表示构造的文章到第i位时处在字典树的第j个节点的不包含单词的数量,最后用总的数量26^m //-d[m][0~sz]即可.其中不能走单词结尾的节点以及他们的fail.这里其实要把每个节点都连向他的26个后继,但是不连也没关系可以看作 //那些没出现的节点都转移成了0节点. #include<iostream> #include<cstdio> #include<cstring> #include&l

bzoj 2434 AC自动机+树状数组

2434: [Noi2011]阿狸的打字机 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 3493  Solved: 1909[Submit][Status][Discuss] Description 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母. 经阿狸研究发现,这个打字机是这样工作的: l 输入小写字母,打字机的一个凹槽中会加入这个字母(这个字母加在凹槽

bzoj 1559 AC自动机 + dp

思路:直接在状态图上跑dp,最后枚举一下42种一下的.. 这个枚举有点恶心. #include<bits/stdc++.h> #define LL long long #define ll long long #define fi first #define se second #define mk make_pair #define PII pair<int, int> #define y1 skldjfskldjg #define y2 skldfjsklejg using n

bzoj 2938 AC自动机

根据题意建出trie图,代表单词的点不能走,直接或间接指向它的点也不能走.这样的话如果能在图中找到一个环的话就是TAK,否则是NIE. 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<queue> 6 #define N 30005 7 using namespace std; 8 int n;bool fla

[BZOJ 3172] [Tjoi2013] 单词 【AC自动机】

题目链接:BZOJ - 3172 题目分析: 题目要求求出每个单词出现的次数,如果把每个单词都在AC自动机里直接跑一遍,复杂度会很高. 这里使用AC自动机的“副产品”——Fail树,Fail树的一个性质是,一个字符串出现的次数,就等于以它的结点为根的Fail树中的子树中所有结点的 Cnt 和. 所以把每个单词插入的时候每个字符都 ++Cnt ,在建 Fail 的时候将结点依次压入一个栈,最后再从栈顶开始弹栈,更新栈顶元素的 Fail 的 Cnt 值,这样就是自叶子节点向上更新了. 我开始写的时候

bzoj 3172 后缀数组|AC自动机

后缀数组或者AC自动机都可以,模板题. /************************************************************** Problem: 3172 User: BLADEVIL Language: C++ Result: Accepted Time:424 ms Memory:34260 kb ****************************************************************/ //By BLADEVI

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: [Tjoi2013]单词(AC自动机||AC自动机+fail树||后缀数组暴力||后缀数组+RMQ+二分等五种姿势水过)

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