P3121 [USACO15FEB]审查(黄金)Censoring (Gold)
思路:
首先构造AC自动机,然后那串去匹配,并且记录一下每一个字符匹配时在AC自动机上的位置。
如果成功匹配一个单词,那么就需要从串中删除这个单词,并且从之前标记的位置开始匹配。
因为单词的长度我们知道,所以直接利用一个数组模拟的栈来搞就行。
代码如下:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5+5;
int n,top;
char s[N],t[N];
int sta[N];
int Skip[N];
queue <int> q;
struct Aho_Corasick{
int Size;
int ch[N][30];
int val[N];
int fail[N];
void init(){
Size=-1;
newnode();
}
int newnode(){
memset(ch[++Size],0,sizeof(ch[0]));
val[Size]=fail[Size]=0;
return Size;
}
void insert(char *s){
int l=strlen(s);
int u=0;
for(int i=0;i<l;i++){
int idx=s[i]-'a';
if(!ch[u][idx]) ch[u][idx]=newnode();
u=ch[u][idx];
}
val[u]=l;
}
void Getfail(){
while(!q.empty()) q.pop();
for(int i=0;i<26;i++){
if(ch[0][i]) q.push(ch[0][i]);
}
while(!q.empty()){
int cur=q.front();q.pop();
for(int i=0;i<26;i++){
if(ch[cur][i]){
fail[ch[cur][i]]=ch[fail[cur]][i];
q.push(ch[cur][i]);
}else{
ch[cur][i]=ch[fail[cur]][i];
}
}
}
}
void query(char *s){
int l=strlen(s);
int u=0;
for(int i=0;i<l;i++){
int idx = s[i]-'a';
sta[++top]=i;
int cur = ch[u][idx];
Skip[top]=cur;
if(val[cur]){
//cout<<top<<" "<<val[cur]<<endl;
top-=val[cur];
u=Skip[top];
continue ;
}
u=cur;
}
}
}ac;
int main(){
//freopen("testdata.in","r",stdin);
//freopen("testdate",)
scanf("%s",s);
scanf("%d",&n);
ac.init();
for(int i=1;i<=n;i++){
scanf("%s",t);
ac.insert(t);
}
ac.Getfail();
ac.query(s);
for(int i=1;i<=top;i++) printf("%c",s[sta[i]]);
printf("\n");
return 0;
}
/*
abbababaab
3
baa
bab
aab
*/