BZOJ2938 [Poi2000]病毒 【AC自动机】
2018-01-26 12:34
323 查看
题目
二进制病毒审查委员会最近发现了如下的规律:某些确定的二进制串是病毒的代码。如果某段代码中不存在任何一段病毒代码,那么我们就称这段代码是安全的。现在委员会已经找出了所有的病毒代码段,试问,是否存在一个无限长的安全的二进制代码。
示例:
例如如果{011, 11, 00000}为病毒代码段,那么一个可能的无限长安全代码就是010101…。如果{01, 11, 000000}为病毒代码段,那么就不存在一个无限长的安全代码。
任务:
请写一个程序:
l 读入病毒代码;
l 判断是否存在一个无限长的安全代码;
l 将结果输出
输入格式
第一行包括一个整数n,表示病毒代码段的数目。以下的n行每一行都包括一个非空的01字符串——就是一个病毒代码段。所有病毒代码段的总长度不超过30000。
输出格式
你应在在文本文件WIN.OUT的第一行输出一个单词:
l TAK——假如存在这样的代码;
l NIE——如果不存在。
输入样例
3
01
11
00000
输出样例
NIE
题解
我们对所有串建出一个ACM,我们要做的就是在ACM上找一个路径,使得路径包含环且不包含结束节点
对于所有fail指针指向的节点,如果形成串,那么该节点也不能选,因为fail指针指向的为当前串的前缀
建完机后跑一跑dfs检查环就好了
#include<iostream> #include<cmath> #include<queue> #include<cstdio> #include<cstring> #include<algorithm> #define LL long long int #define REP(i,n) for (int i = 1; i <= (n); i++) #define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt) #define BUG(s,n) for (int i = 1; i <= (n); i++) cout<<s[i]<<' '; puts(""); using namespace std; const int maxn = 300005,maxm = 1000005,INF = 1000000000; inline int read(){ int out = 0,flag = 1; char c = getchar(); while (c < 48 || c > 57) {if (c == '-') flag = -1; c = getchar();} while (c >= 48 && c <= 57) {out = (out << 3) + (out << 1) + c - '0'; c = getchar();} return out * flag; } int ch[maxn][2],siz,fail[maxn],val[maxn]; char s[maxn]; void insert(char* P){ int u = 0,len = strlen(P),x; for (int i = 0; i < len; i++){ x = P[i] - '0'; if (!ch[u][x]) ch[u][x] = ++siz; u = ch[u][x]; } val[u] = 1; } void getfail(){ queue<int> q; fail[0] = -1; for (int i = 0; i < 2; i++) if (ch[0][i]) q.push(ch[0][i]); int u; while (!q.empty()){ u = q.front(); q.pop(); for (int i = 0; i < 2; i++){ int v = ch[u][i]; if (!v) {ch[u][i] = ch[fail[u]][i]; continue;} int k = fail[u]; fail[v] = ch[k][i]; val[v] |= val[ch[k][i]]; q.push(v); } } } bool flag; int vis[maxn],ins[maxn]; bool dfs(int u){ ins[u] = true; for (int i = 0; i < 2; i++){ int v = ch[u][i]; if (ins[v]) return true; if (vis[v] || val[v]) continue; vis[v] = true; if (dfs(v)) return true; } ins[u] = false; return false; } int main(){ int n = read(); while (n--) scanf("%s",s),insert(s); getfail(); dfs(0) ? puts("TAK") : puts("NIE"); return 0; }
相关文章推荐
- BZOJ2938 [Poi2000]病毒 解题报告【AC自动机】【DFS】
- BZOJ2938[Poi2000]病毒 AC自动机
- AC自动机【poi2000】bzoj2938 病毒
- 【bzoj2938】[Poi2000]病毒 AC自动机
- [bzoj2938][Poi2000]病毒 AC自动机
- 【bzoj2938】[Poi2000]病毒 AC自动机
- bzoj2938[Poi2000]病毒 AC自动机+dfs
- bzoj2938【Poi2000】病毒
- BZOJ_2938_[Poi2000]病毒_AC自动机
- bzoj2938 [Poi2000]病毒 AC自动机+DP
- bzoj2938【Poi2000】病毒
- bzoj2938 [Poi2000]病毒 ac自动机
- BZOJ2938 POI2000 病毒 题解&代码
- 洛古2444 [POI2000]病毒 ac自动机
- BZOJ 2938 [Poi2000]病毒(AC自动机)
- BZOJ2938 POI2000 病毒 补全AC自动机 Trie图判环
- bzoj2938 [Poi2000]病毒(AC自动机+DFS找环)
- [bzoj2938][Poi2000]病毒_AC自动机
- [luoguP2444] [POI2000]病毒(AC自动机 + dfs)
- 【bzoj2938】[Poi2000]病毒 trie图+dfs