2018 牛客网暑期ACM多校训练营(第九场) Typing practice(AC自动机)

本文介绍如何使用AC自动机优化单词匹配问题,通过构建Trie图并利用失败指针更新节点答案,实现输入字母后快速计算最少需要添加的单词数。代码示例展示了完整的AC自动机构建及查询过程。

题意:

给了N个单词,NiuNiu想输入一些字母,想知道在输入这些字母后最少需要多加多少个单词才能使得存在后缀使得与N个单词中的一个匹配。

 

思路:

把这个N个单词建个AC自动机,在建的过程中每个节点都记录最少要加多少个字母的答案,建个trie图,在跑fail的时候,更新每个节点的答案。最后统计答案的时候模拟一下栈操作就好了。

 

代码:

#include <bits/stdc++.h>

using namespace std;
const int maxn=1e5+5;
const int inf=0x3f3f3f3f;
char a[maxn];
int ch[maxn][26];
int que[maxn];
int fail[maxn];
int len[maxn];
char s[maxn];
int tot;
int newnode()
{
    ++tot;
    return tot;
}
void ins(char s[])
{
    int root=0;
    int l=strlen(s);
    int i;
    for(i=0;s[i];i++)
    {
        int x=s[i]-'a';
        len[root]=min(len[root],l-i);
        if(!ch[root][x])
            ch[root][x]=newnode();
        root=ch[root][x];
    }
    len[root]=min(len[root],l-i);
}
void build_fail()
{
    int head=0,tail=0;
    for(int i=0;i<26;i++)
    {
        if(ch[0][i])
        {
            que[++tail]=ch[0][i];
        }
    }
    while(head<tail)
    {
        int u=que[++head];
        for(int i=0;i<26;i++)
        {
            if(ch[u][i])
            {
                fail[ch[u][i]]=ch[fail[u]][i];
                que[++tail]=ch[u][i];
            }
            else ch[u][i]=ch[fail[u]][i];
            len[ch[u][i]]=min(len[ch[u][i]],len[fail[ch[u][i]]]);
        }
    }
}
int main()
{
    int n;
    memset(len,inf,sizeof(len));
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%s",s);
        ins(s);
    }
    build_fail();
    scanf("%s",s);
    int root=0;
    int sta[maxn];
    int p=0;
    sta[++p]=root;
    printf("%d\n",len[sta[p]]);
    for(int i=0;s[i];i++)
    {
        if(s[i]=='-')
        {
            if(p) p--;
            root=sta[p];
        }
        else
        {
            int x=s[i]-'a';
            root=ch[root][x];
            sta[++p]=root;
        }
        printf("%d\n",len[sta[p]]);
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值