【POI2000】病毒
AC自動機
(注:POI 波蘭OI)
先建立AC自動機,一般的題都是要儘可能地匹配,而這道題是儘可能不匹配。
就用DFS找一下有無從根出發不經過危險節點(末尾標上val的節點),的一個環即可。
貌似在getfail()時就已經把一些兒子連到了失敗指針的,具體的奧祕還不是很清楚。
注意:
- 如果一個節點的失敗指針是危險節點,那麼這個點也是危險節點。
- DFS時要記錄兩個數組,vis(是否在當前的環中,用完要清零),app(是否搜到過,不用清零),我們每次只搜索沒出現過的節點,若搜到已在環中就表示找到環了,推出程序即可。
#include<bits/stdc++.h>
using namespace std;
const int M=1e5+5,N=3e4+5;
int n,siz=1,ch[N][2],val[N],fail[N];
char s[N];
void insert(){
int len=strlen(s+1);
int p=1;
for(int i=1;i<=len;i++){
int c=s[i]-'0';
if(!ch[p][c])ch[p][c]=++siz;
p=ch[p][c];
}
val[p]++;
}
void getfail(){
queue<int>q;
fail[1]=0;
for(int i=0;i<=1;i++)
if(ch[1][i]){
fail[ch[1][i]]=1;
q.push(ch[1][i]);
}
while(!q.empty()){
int c=q.front();q.pop();
for(int i=0;i<=1;i++){
int u=ch[c][i];
if(!u){
ch[c][i]=ch[fail[c]][i];//與失配指針連邊
continue;
}
int v=fail[c];
fail[u]=ch[v][i];
if(val[ch[v][i]])val[u]=1;
q.push(u);
}
}
}
int vis[N],app[N];
void dfs(int x){
vis[x]=app[x]=1;
for(int i=0;i<=1;i++){
if(vis[ch[x][i]]){
printf("TAK");
exit(0);
}
else if(!val[ch[x][i]]&&!app[ch[x][i]])dfs(ch[x][i]);
}
vis[x]=0;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%s",s+1);
insert();
}
getfail();//
dfs(1);
printf("NIE");
return 0;
}