【题解】P2444 病毒

【题解】[P2444 POI2000]病毒

一道\(ac\)自动机好题...

考虑危险的字符串是什么意思,就是在这个文本串中有模式串的匹配,这样的匹配可以通过\(ac\)自动机完成。

那么给定一个字符串如何判断是否有病毒,直接就是看ac自动机是否匹配成功。

考虑“无限长的安全字符串”代表什么意思,就是在\(ac\)自动机找到一个环。可以用阉割版的\(tarjin\)

#include<bits/stdc++.h>

using namespace std;
#define RP(t,a,b) for(register int t=(a),edd=(b);t<=edd;++t)
#define DRP(t,a,b) for(register int t=(a),edd=(b);t>=edd;--t)
#define ERP(t,a) for(register int t=head[a];t;t=e[t].nx)
#define Max(a,b) ((a)<(b)?(b):(a))
#define Min(a,b) ((a)<(b)?(a):(b))
#define midd register int mid=(l+r)>>1
#define TMP template < class ccf >

TMP inline ccf qr(ccf b){
    char c=getchar();
    int q=1;
    ccf x=0;
    while(c<48||c>57)
    q=c==45?-1:q,c=getchar();
    while(c>=48&&c<=57)
    x=x*10+c-48,c=getchar();
    return q==-1?-x:x;
}

const int maxac=30005;
int n;
string x;
struct AC{
    int son[2];
    int fail;int cnt;
    inline int& operator [](int o){
    return son[o&1];
    }
    inline int& operator [](char o){
    return son[(o-‘0‘)&1];
    }
}ac[maxac];
int act;

inline void build(int lit){
    int now=0;
    RP(t,0,lit-1){
    if(!ac[now][x[t]])
        ac[now][x[t]]=++act;
    now=ac[now][x[t]];
    }
    ac[now].cnt++;
    //cout<<"build="<<now<<endl;
}

queue< int > q;
inline void gen(){
    RP(t,0,1)
    if(ac[0][t])
        q.push(ac[0][t]);
    while(!q.empty()){
    int now=q.front();
    q.pop();
    RP(t,0,1){
        if(ac[now][t]){
        ac[ac[now][t]].fail=ac[ac[now].fail][t];
        ac[ac[now][t]].cnt|=ac[ac[ac[now].fail][t]].cnt;
        q.push(ac[now][t]);
        }
        else
        ac[now][t]=ac[ac[now].fail][t];
    }
    }
}

bool in[maxac];
bool usd[maxac];
void dfs(int now){
    usd[now]=in[now]=1;
    RP(t,0,1){
    if(in[ac[now][t]])
        puts("TAK"),exit(0);
    if(!ac[ac[now][t]].cnt)
        dfs(ac[now][t]);
    }
    in[now]=0;
}

int main(){
#ifndef ONLINE_JUDGE
    freopen("in.in","r",stdin);
    freopen("out.out","w",stdout);
#endif
    n=qr(1);
    RP(t,1,n){
    cin>>x;
    build(x.length());
    }
    gen();
    if(!ac[0].cnt)
    dfs(0);
    puts("NIE");
    return 0;
}

原文地址:https://www.cnblogs.com/winlere/p/10355415.html

时间: 2024-10-17 19:09:00

【题解】P2444 病毒的相关文章

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

P2444 [POI2000]病毒

题目描述 二进制病毒审查委员会最近发现了如下的规律:某些确定的二进制串是病毒的代码.如果某段代码中不存在任何一段病毒代码,那么我们就称这段代码是安全的.现在委员会已经找出了所有的病毒代码段,试问,是否存在一个无限长的安全的二进制代码. 示例: 例如如果{011, 11, 00000}为病毒代码段,那么一个可能的无限长安全代码就是010101….如果{01, 11, 000000}为病毒代码段,那么就不存在一个无限长的安全代码. 任务: 请写一个程序: 1.在文本文件WIR.IN中读入病毒代码:

【题解】Puzzle [Uva1399]

[题解]Puzzle [Uva1399] 传送门:\(\text{Puzzle [Uva1399]}\) [题目描述] 给定 \(m\) 和 \(n\),表示有 \(m\) 种不同的字符(大写字母\(A,B,C \cdots\)),\(n\) 个禁止串,请构造一个不包含任何禁止串的最长字符串 并将其输出.如果可以无限长或者无解则输出 \(No\),如果存在多解则输出字典序最大的一种. [输入] 第一行一个整数T表示数据组数. 接下来每组数据第一行为两个整数 \(m,n\),接下来 \(n\) 行

AC自动机 病毒侵袭 hdu2896

和hdu2222题相似的水题 提示: 1)连着RE了好多发,没想明白,看了一下网上题解才知道,输入的不一定都是字母,所以next要开100!!!!!!! #include <stdio.h> #include <string.h> int tot; char str[10005]; int t; //int time[100]; struct trie { trie *fail; trie *next[100]; int num; trie() { for(int i=0; i&l

【HDU2896】病毒侵袭 AC自动机

[HDU2896]病毒侵袭 Problem Description 当太阳的光辉逐渐被月亮遮蔽,世界失去了光明,大地迎来最黑暗的时刻....在这样的时刻,人们却异常兴奋--我们能在有生之年看到500年一遇的世界奇观,那是多么幸福的事儿啊~~但网路上总有那么些网站,开始借着民众的好奇心,打着介绍日食的旗号,大肆传播病毒.小t不幸成为受害者之一.小t如此生气,他决定要把世界上所有带病毒的网站都找出来.当然,谁都知道这是不可能的.小t却执意要完成这不能的任务,他说:"子子孙孙无穷匮也!"(愚

【BZOJ3779】重组病毒 LCT+DFS序

[BZOJ3779]重组病毒 Description 黑客们通过对已有的病毒反编译,将许多不同的病毒重组,并重新编译出了新型的重组病毒.这种病毒的繁殖和变异能力极强.为了阻止这种病毒传播,某安全机构策划了一次实验,来研究这种病毒.实验在一个封闭的局域网内进行.局域网内有n台计算机,编号为1~n.一些计算机之间通过网线直接相连,形成树形的结构.局域网中有一台特殊的计算机,称之为核心计算机.根据一些初步的研究,研究员们拟定了一个一共m步的实验.实验开始之前,核心计算机的编号为1,每台计算机中都有病毒

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

题目 二进制病毒审查委员会最近发现了如下的规律:某些确定的二进制串是病毒的代码.如果某段代码中不存在任何一段病毒代码,那么我们就称这段代码是安全的.现在委员会已经找出了所有的病毒代码段,试问,是否存在一个无限长的安全的二进制代码. 示例: 例如如果{011, 11, 00000}为病毒代码段,那么一个可能的无限长安全代码就是010101-.如果{01, 11, 000000}为病毒代码段,那么就不存在一个无限长的安全代码. 任务: 请写一个程序: l 读入病毒代码: l 判断是否存在一个无限长的

【bzoj2938】【poi2000】病毒

题解: 对病毒串建立ac自动机: 有一个无限长的串等价于可以一直在自动机上匹配,等价于自动机上的转移有环: 当然前提是去掉病毒节点的fail子树: 写一个dfs记录是否在栈中,来过没有找到就不必再来了再记录一个vis保证复杂度; 然而......我在找环的时候呆了很久,最后写了tarjan: 如果你也是有些tarjan的危险想法的话注意特判转移的自环的情况: 1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N=30010