1. 程式人生 > >[bzoj3940][Usaco2015 Feb]Censoring

[bzoj3940][Usaco2015 Feb]Censoring

front print body ring 就是 -- lin names rst

最近做題成雙成對?不是雙倍經驗就是兩題同解。

3940 3942

給定字典,給定字符串,刪去字符串中所有字典內單詞。保證不會出現二者包含狀況。$n \leq 1e5,\sum len \leq 1e5$

AC自動機裸題。build出AC自動機後從左到右插入文本串,同時邊匹配邊push進棧裏。匹配成功就彈棧。

註意要記錄匹配到第幾個字符的時候,AC自動機指針(我管那個一直蹦的東西就叫指針了?)指到哪裏。彈棧之後要指針也要跳回來。

#include<bits/stdc++.h>
#define x first
#define y second
using namespace std;
typedef pair
<int,int> P; const int N=100010; struct ACAM{ int ch[N][26],cnt[N],f[N]; int sz,rt; void init(){ memset(ch,-1,sizeof ch); memset(cnt,0,sizeof cnt); memset(f,0,sizeof f); sz=rt=0; } void ins(char *s){ int n=strlen(s),u=rt; for(int i=0;i<n;i++){
int c=s[i]-a; if(!~ch[u][c]) ch[u][c]=++sz; u=ch[u][c]; } cnt[u]=n; } void build(){ queue<int>q; while(!q.empty())q.pop(); for(int i=0;i<26;i++) if(~ch[rt][i]) f[ch[rt][i]]=rt,q.push(ch[rt][i]);
else ch[rt][i]=rt; while(!q.empty()){ int u=q.front();q.pop(); for(int i=0;i<26;i++){ int v=ch[u][i]; if(~v){ int now=f[u]; while(f&&!~ch[now][i])now=f[now]; f[v]=ch[now][i];q.push(v); } else ch[u][i]=ch[f[u]][i]; } } } void query(char *s){ int n=strlen(s); stack<P>S;int u=0; while(!S.empty())S.pop(); for(int i=0;i<n;i++){ int c=s[i]-a; while(u&&!~ch[u][c])u=f[u]; u=ch[u][c];S.push(P(c,u)); if(cnt[u]){ for(int j=1;j<=cnt[u];j++) S.pop(); if(!S.empty())u=S.top().y; else u=0; } } vector<char>ans; while(!S.empty()) ans.push_back(S.top().x+a),S.pop(); for(int i=ans.size()-1;~i;i--) printf("%c",ans[i]); } }Aho; char str[N],s[N]; int main(){ scanf("%s",str); int n;scanf("%d",&n); Aho.init(); for(int i=1;i<=n;i++){ memset(s,0,sizeof s); scanf("%s",s); Aho.ins(s); } Aho.build(); Aho.query(str); }

[bzoj3940][Usaco2015 Feb]Censoring