2018 牛客網暑期ACM多校訓練營(第九場) Typing practice(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;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章