题目描述
二进制病毒审查委员会最近发现了如下的规律:某些确定的二进制串是病毒的代码。如果某段代码中不存在任何一段病毒代码,那么我们就称这段代码是安全的。现在委员会已经找出了所有的病毒代码段,试问,是否存在一个无限长的安全的二进制代码。
示例:
例如如果{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——如果不存在。
输入输出样例
输入样例#1: 复制
3 01 11 00000
输出样例#1: 复制
NIE
多串匹配问题首选AC自动机。不过这题是匹配不上,其他题是匹配得上。再想想就能发现只需要在AC自动机上走出一个环,不碰到所有表示匹配成功得状态得节点就是可以构造出来的。那么我们把AC自动机这样处理:对于一个点如果0,1的转移都是正常边就连原来的点,如果0,1没有转移那么就用AC自动机的匹配操作跳出失配后转到的节点连边。最后把匹配点标记找有没有环就行了。
#include<cstdio> #include<iostream> #include<cstring> #include<queue> #include<stack> using namespace std; const int maxn = 4e6 + 5; struct edge { int v, next; }e[maxn << 1]; int head[maxn], cnt, dfn[maxn], vis[maxn]; void adde(const int &u, const int &v) { e[++cnt] = (edge) {v, head[u]}; //cerr << u << "--->" << v << endl; head[u] = cnt; } char s[maxn], blk[maxn]; namespace AC { int trie[maxn][2], fa[maxn], cnt = 1; void insert(char * s) { int len = strlen(s), id, now = 1; for(register int i = 0; i < len; ++i) { id = s[i] - '0'; if(trie[now][id]) now = trie[now][id]; else now = trie[now][id] = ++cnt; } blk[now] = 1; } void create() { queue<int > q; q.push(1); while(!q.empty()) { int u = q.front(), v, p; q.pop(); for(register int i = 0; i < 2; ++i) { if(!trie[u][i]) continue; v = trie[u][i], p = fa[u]; while(p && !trie[p][i]) p = fa[p]; if(p) fa[v] = trie[p][i]; else fa[v] = 1; q.push(v), blk[v] |= blk[fa[v]]; } } } void con() { queue<int > q; q.push(1); while(!q.empty()) { int u = q.front(), p; q.pop(); for(register int i = 0; i < 2; ++i) { p = fa[u]; if(trie[u][i]) adde(u, trie[u][i]), q.push(trie[u][i]); else { while(p && !trie[p][i]) p = fa[p]; if(p) adde(u, trie[p][i]); else adde(u, 1); } } } } } int flag = 0; void dfs(int u) { if(flag) return ; dfn[u] = 1, vis[u] = 1; //cerr << u << "--in" << endl; for(register int i = head[u]; i; i = e[i].next) { int v = e[i].v; if(blk[v]) continue; if(dfn[v]) { if(vis[v]) flag = 1; continue; } dfs(v); } vis[u] = 0; } int n; int main() { scanf("%d", &n); while(n--) { scanf("%s", s); AC::insert(s); } AC::create(); AC::con(), dfs(1); if(flag) printf("TAK"); else printf("NIE"); return 0; }
没有帐号? 立即注册