[Usaco2015 Feb]Censoring

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq872425710/article/details/81835991

题目大意

给你一个大字符串,和若干个小字符串,要求你把大字符串里面所有的小字符串都删掉,(可以能会有删完组成新字符串的情况)。

思路:

很容易想到吧小字符串建一个ac自动机,不过匹配的时候每次都只条fail就会特别慢,会超时,所以我们记录出来每个位置下一次和上一次会跳到哪里,然后就可以了。

程序:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<cstring>
#define N 100005
int t[N][27],val[N],fail[N],nx[N],ls[N],pos[N],lens[N];
int tot,n,m;
std::queue<int>q;
char s[N],c[N];

void ins(){
    int now=0,len=strlen(c);
    for (int i=0;i<len;i++){
        int u=c[i]-'a';
        if (t[now][u]) now=t[now][u];
        else now=t[now][u]=++tot;
    }
    val[now]=1; lens[now]=len;
}

void getfail(){
    for (int i=0;i<26;i++)
      if (t[0][i]) q.push(t[0][i]);
    while (!q.empty()){
        int r=q.front();
        q.pop();
        for (int i=0;i<26;i++)
        {
            int u=t[r][i],v=fail[r];
            if (!u) {
                t[r][i]=t[v][i];
                continue;
            }
            q.push(u);
            while (v&&!t[v][i]) v=fail[v];
            v=t[v][i];
            fail[u]=v;
            if (val[v]) val[u]=1;
        }
    }
}

int main(){
    freopen("a.in","r",stdin);
    scanf("%s",s+1);
    n=strlen(s+1);
    scanf("%d",&m);
    for (int i=1;i<=m;i++){
        scanf("%s",c);
        ins();
    }
    getfail();
    for (int i=0;i<=n;i++) nx[i]=i+1;
    for (int i=1;i<=n+1;i++) ls[i]=i-1;
    int p=0;
    for (int i=1;i<=n;i++){
        pos[i]=p=t[p][s[i]-'a'];
        if (val[p]){
            int now=i;
            for (int j=1;j<=lens[p];j++) ls[nx[now]]=ls[now],nx[ls[now]]=nx[now],now=ls[now];
            p=pos[now]; 
        }
    }
    for (int i=nx[0];i!=n+1;i=nx[i]) printf("%c",s[i]);
}
阅读更多
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页