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;
}

原文地址:https://www.cnblogs.com/Mychael/p/8358981.html

时间: 2024-08-08 16:26:36

BZOJ2938 [Poi2000]病毒 【AC自动机】的相关文章

BZOJ 2938 Poi2000 病毒 AC自动机+拓扑排序

题目大意:给定n个01串,问是否存在一个无限长的01串,不包含这n个01串中的任何一个 建出Trie图之后判环即可 我这傻逼一开始居然跑了一个DFS去判环23333 #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define M 30300 using namespace std; int n; char s[M]; namespace Aho_C

Hnu 10104 病毒 (AC自动机+dfs)

病毒 Time Limit: 1000ms, Special Time Limit:2500ms, Memory Limit:32768KB Total submit users: 41, Accepted users: 23 Problem 10104 : No special judgement Problem description 二进制病毒审查委员会最近发现了如下的规律:某些确定的二进制串是病毒的代码.如果某段代码中不存在任何一段病毒代码,那么我们就称这段代码是安全的.现在委员会已经找

BZOJ2938: [Poi2000]病毒

传送门 AC自动机上的各种处理一直让我很迷.一个主要懵逼的点是不清楚对于不存在的字母所对应的方案如何处理.做了两道题大概比较清楚了. 其实对于不存在的字母节点不需要特殊的处理.因为如果累加方案的话,其方案会自动累加到$root$节点.而其fail指针也会自动指向自己. 另外这道题的判环参考了黄学长的代码,类似于一个简化版的tarjan. //BZOJ 2938 //by Cydiater //2016.10.18 #include <iostream> #include <cstdio&

[日常摸鱼][POI2000]病毒-Tire图(AC自动机)+dfs

https://www.luogu.org/problemnew/show/P2444 (没有bzoj权限号T_T) 字符串题对我这种傻逼来说真是太难了x 题意:输入$n$个01组成的模式串串,判断是否存在一个无限长的01串满足任何给定的模式串都不是这个串的子串,$n \leq 2000,\sum len(str) \leq 30000$ 首先用模式串构造出AC自动机(其实应该叫Trie图),题目要求的串如果存在,那就相当于在Trie图上存在一个环,这个环不包含任何一个模式串,所以只要构造出来T

HDU 2896 病毒侵袭 AC自动机题解

本题是在text里面查找key word的增强版,因为这里有多个text. 那么就不可以简单把Trie的叶子标志记录修改成-1进行加速了,可以使用其他技术,我直接使用个vis数组记录已经访问过的节点,达到加速效果,速度还算挺快的. 不过看discuss里面有人直接使用Trie,做出了140ms的速度,而且他的程序严格来说并不正确,可见本题的数据很水啊.Trie的时间效率肯定比AC自动机低,但是在数据很水的特殊情况下,Trie的速度也可以很快的. 注意两个细节: 1 病毒也需要安装顺序输出,不小心

HDU 3065 病毒侵袭持续中 AC自动机题解

其实本题比HDU的病毒侵袭1还简单,不过有一个陷阱卡到我了:就是搜索text的时候,当遇到的字母不是大写字母的时候,那么就要重新从根节点开始搜索,否则就会答案错误. 那么一点陷阱,居然没想到啊. 教训啊:看来对不太平常的地方,需要更加深入的思考,才能发现其中的陷阱,否则就WA了. #include <stdio.h> #include <string.h> #include <queue> using std::queue; const int MAX_N = 1001

HDU 3065 病毒侵袭持续中(AC自动机)

病毒侵袭持续中 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 15137    Accepted Submission(s): 5161 Problem Description 小t非常感谢大家帮忙解决了他的上一个问题.然而病毒侵袭持续中.在小t的不懈努力下,他发现了网路中的"万恶之源".这是一个庞大的病毒网站,他有着好多好多

hdu 2896 病毒侵袭 AC自动机(查找包含哪些子串)

病毒侵袭 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 19465    Accepted Submission(s): 4814 Problem Description 当太阳的光辉逐渐被月亮遮蔽,世界失去了光明,大地迎来最黑暗的时刻....在这样的时刻,人们却异常兴奋——我们能在有生之年看到500年一遇的世界奇观,那是多么幸福的事儿

[hdu 2896] 病毒侵袭 [ac自动机][病毒特征码匹配]

病毒侵袭 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 20728    Accepted Submission(s): 5058 Problem Description 当太阳的光辉逐渐被月亮遮蔽,世界失去了光明,大地迎来最黑暗的时刻....在这样的时刻,人们却异常兴奋--我们能在有生之年看到500年一遇的世界奇观,那是多么幸福的事