• BZOJ2938 [Poi2000]病毒 【AC自动机】


    题目

    二进制病毒审查委员会最近发现了如下的规律:某些确定的二进制串是病毒的代码。如果某段代码中不存在任何一段病毒代码,那么我们就称这段代码是安全的。现在委员会已经找出了所有的病毒代码段,试问,是否存在一个无限长的安全的二进制代码。
    示例:
    例如如果{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;
    }
    
    
  • 相关阅读:
    js遍历多层对象的键值对
    JS HEX十六进制与RGB, HSL颜色的相互转换【转】
    TortoiseSVN打分支、合并分支、切换分支【转】
    grid.containLabel
    安装谷歌vue-devtools调试插件
    使用Echarts遇到的问题
    理解js编程中函数的副作用
    git 镜像下载和安装
    欢迎来到博客园的世界
    c#制作一个屏幕保护程序
  • 原文地址:https://www.cnblogs.com/Mychael/p/8358981.html
Copyright © 2020-2023  润新知