P3121 [USACO15FEB]审查(黄金)Censoring (Gold)

传送门

显然是个AC自动机

考虑删除完单词后怎么回到前面

可以开一个栈

存到每个字符时匹配的位置

然后就可以搞了

答案也用一个栈存

每次删单词时把答案栈里的单词也弹出来

最后输出栈里的单词就好了

数据有毒,输出后要换行,不然会WA...

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
using namespace std;
const int N=2e5+7;
const int M=2e6+7;
int n,l[N];//l存每个单词长度,方便弹出栈
char s[N],a[N];
int c[M][27],pd[M],fail[M],cnt,g[M];//AC自动机
inline void ins(int k)//插入第k个单词
{
    int u=0;
    for(int i=0;i<l[k];i++)
    {
        int v=a[i]-'a'+1;
        if(!c[u][v]) c[u][v]=++cnt;
        u=c[u][v];
    }
    pd[u]=k;
}
queue <int> q;
inline void pre()//预处理
{
    for(int i=1;i<=26;i++) if(c[0][i]) q.push(c[0][i]);
    while(!q.empty())
    {
        int u=q.front(); q.pop();
        for(int i=1;i<=26;i++)
        {
            int v=c[u][i];
            if(!v) c[u][i]=c[fail[u]][i];
            else
            {
                fail[v]=c[fail[u]][i];
                g[v]=pd[fail[v]] ? fail[v] : g[fail[v]];
                q.push(v);
            }
        }
    }
}
char q2[N];//答案栈
int q1[N],t1,t2;
inline void query()
{
    int u=0,len=strlen(s);
    for(int i=0;i<len;i++)
    {
        int v=s[i]-'a'+1;
        u=c[u][v];
        q1[++t1]=u; q2[++t2]=s[i];//入栈
        for(int j=u;j;j=g[j])
            if(pd[j])//如果有单词就弹出
            {
                t1-=l[pd[j]];
                t2-=l[pd[j]];
                u=q1[t1];
                break;//题目保证任何单词都不是其他单词的子串
            }
    }
    for(int i=1;i<=t2;i++) printf("%c",q2[i]);
    printf("\n");//坑点
}
int main()
{
    scanf("%s",s);
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        scanf("%s",a); l[i]=strlen(a);
        ins(i);
    }
    pre();
    query();
    return 0;
}

 

posted @ 2018-09-22 09:40  LLTYYC  阅读(191)  评论(0编辑  收藏  举报