1. 程式人生 > >bzoj2938 poi病毒 AC自動機

bzoj2938 poi病毒 AC自動機

esp ace c++ == roo mes oid 就是 char

題目傳送門

思路:

  要求構建一個字符串,使得這個字符串不包含給出的任意一個單詞。

  如果我們已經構建出了一個安全代碼,放在ac自動機上跑,那麽我們必定不能得到任何一個字符串,此時我們得到的fail指針必定是在一個環上循環,並且這個環不包含單詞的末尾。

  我們也知道fail指針最後是會指回0點的,那麽此時我們其實就是要求一個環,這個換不包含單詞末尾即可。加一個優化就是,如果fail指針指向的地方是末尾,那麽這個地方等同於末尾。

技術分享圖片
#include<bits/stdc++.h>
#define clr(a,b) memset(a,b,sizeof(a))
using
namespace std; typedef long long ll; const int maxn=1000010; char s[maxn],p[maxn]; int trie[maxn][26],cntword[maxn],fail[maxn],cnt=0; int n; bool vis[maxn],ins[maxn]; void insert(char *s){ int root=0; int si=strlen(s); for(int i=0;i<si;i++) { int Next=s[i]-0;
if(!trie[root][Next])trie[root][Next]=++cnt; root=trie[root][Next]; } cntword[root]++; } void getfail(){ queue<int >q; for(int i=0;i<=1;i++) { if(trie[0][i]){ q.push(trie[0][i]); } } while(!q.empty()) {
int now=q.front(); q.pop(); for(int i=0;i<=1;i++) { if(trie[now][i]){ fail[trie[now][i]]=trie[fail[now]][i]; if(cntword[fail[trie[now][i]]])cntword[trie[now][i]]=1;//如果fail指針指向的是病毒的末尾,那麽這個也是病毒 q.push(trie[now][i]); }else{ trie[now][i]=trie[fail[now]][i]; } } } } void init(){ clr(trie,0); clr(cntword,0); clr(ins,0),clr(vis,0); } bool dfs(int u) { ins[u]=1; for(int i=0;i<=1;i++) { int v=trie[u][i]; if(ins[v]==1)return true; if(vis[v]||cntword[v])continue; vis[v]=1; if(dfs(v))return true; } ins[u]=0; return false; } int main(){ scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%s",p); insert(p); } fail[0]=0; getfail(); if(dfs(0))puts("TAK"); else puts("NIE"); }
View Code

bzoj2938 poi病毒 AC自動機