洛谷 P2444 [POI2000]病毒 解題報告
阿新 • • 發佈:2018-08-28
一個 超過 flag ring 這樣的 sed out 匹配 const
P2444 [POI2000]病毒
題目描述
二進制病毒審查委員會最近發現了如下的規律:某些確定的二進制串是病毒的代碼。如果某段代碼中不存在任何一段病毒代碼,那麽我們就稱這段代碼是安全的。現在委員會已經找出了所有的病毒代碼段,試問,是否存在一個無限長的安全的二進制代碼。
示例:
例如如果{011, 11, 00000}為病毒代碼段,那麽一個可能的無限長安全代碼就是010101…。如果{01, 11, 000000}為病毒代碼段,那麽就不存在一個無限長的安全代碼。
任務:
請寫一個程序:
1.在文本文件WIR.IN中讀入病毒代碼;
?2.判斷是否存在一個無限長的安全代碼;
?3.將結果輸出到文件WIR.OUT中。
輸入輸出格式
輸入格式:
在文本文件WIR.IN的第一行包括一個整數n(n\le 2000)(n≤2000),表示病毒代碼段的數目。以下的n行每一行都包括一個非空的01字符串——就是一個病毒代碼段。所有病毒代碼段的總長度不超過30000。
輸出格式:
在文本文件WIR.OUT的第一行輸出一個單詞:
TAK——假如存在這樣的代碼;
NIE——如果不存在。
越想越亂我是得多菜啊
多串匹配,我們選擇AC自動機,要求不能到達單詞末尾且無限長度
等價於在tire圖上尋找經過根的環
弄\(fail\)指針的時候可以多把末尾打一些標記以剪枝
尋找環用tarjan
Code:
#include <cstdio> #include <cstring> const int N=3e5+10; int ch[N][2],is[N],fail[N],tot,n,q[N],l,r,ans=1; char c[N]; void init() { scanf("%s",c+1); int len=strlen(c+1),now=0; for(int i=1;i<=strlen(c+1);i++) { if(!ch[now][c[i]-‘0‘]) ch[now][c[i]-‘0‘]=++tot; now=ch[now][c[i]-‘0‘]; } is[now]=1; } void build() { if(ch[0][0]) q[r]=ch[0][0]; if(ch[0][1]) q[++r]=ch[0][1]; while(l<=r) { int now=q[l++]; for(int i=0;i<=1;i++) { if(ch[now][i]) { fail[ch[now][i]]=ch[fail[now]][i]; is[ch[now][i]]|=is[ch[fail[now]][i]]; q[++r]=ch[now][i]; } else ch[now][i]=ch[fail[now]][i]; } } } int in[N],used[N],flag=0; void dfs(int now) { in[now]=used[now]=1; for(int i=0;i<=1;i++) { int v=ch[now][i]; if(!used[v]&&!is[v]) dfs(v); else if(in[v]) flag=1; } in[now]=0; } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) init(); build(); dfs(0); if(!flag) printf("NIE\n"); else printf("TAK\n"); return 0; }
2018.8.28
洛谷 P2444 [POI2000]病毒 解題報告