BZOJ3172单词(AC自动机)

Posted 小蒟蒻yyb的博客

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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;
}

以上是关于BZOJ3172单词(AC自动机)的主要内容,如果未能解决你的问题,请参考以下文章

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

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

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

BZOJ-3172: [Tjoi2013]单词 (AC自动姬)

BZOJ3172: [Tjoi2013]单词

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