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
二进制病毒审查委员会最近发现了如下的规律:某些确定的二进制串是病毒的代码。如果某段代码中不存在任何一段病毒代码,那么我们就称这段代码是安全的。现在委员会已经找出了所有的病毒代码段,试问,是否存在一个无限长的安全的二进制代码。 例如如果{011, 11, 00000}为病毒代码段,那么一个可能的无限长安全代码就是010101…。如果{01, 11, 000000}为病毒代码段,那么就不存在一个无限长的安全代码。
任务: 请写一个程序: 读入病毒代码; 判断是否存在一个无限长的安全代码; 将结果输出。
Input
第一行包括一个整数n,表示病毒代码段的数目。以下的n行每一行都包括一个非空的01字符串——就是一个病毒代码段。所有病毒代码段的总长度不超过30000。
Output
输出一个单词: TAK——假如存在这样的代码; NIE——如果不存在 
Sample Input
3
01
11
00000
Sample Output
NIE
Problem Source
SDOI
Submit   Discuss   Judge
Status
  Problems  Ranklist 

题目链接

http://acm.hnu.cn/online/?action=problem&type=show&id=10104

思路分析:

仔细分析就会发现,如果在ac自动机上存在一个环,且这个环上没有单词的末尾节点,那么就可以。

为什么连单词的末尾节点也不行。

因为ac自动机上的next指向了的是与它具有最长后缀等于前缀的,如果这个时候后缀指向了单词末尾节点的前面,也就意味着有一个前缀在这个末尾节点的前面,那么这个环总会出现一个单词节点。

所以在dfs的时候,要避开一切的单词末尾节点。

至于dfs的时候,我们要判断的也是一条连续的链上的环,所以在深搜的时候用1去标记,然后回溯的时候,标记成另外一个。

然后没有标记的为0.

这样就可以找到链上成环的节点了。

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#define N 105
#define maxn 30005
using namespace std;
typedef long long ll;
const int mod = 100000;

const char tab = '0';
const int max_next = 2;

int next[maxn][max_next],fail[maxn],num[maxn],siz;

int newnode()
{
    for(int i=0;i<max_next;i++)
        next[siz][i]=0;
    fail[siz]=num[siz]=0;
    return siz++;
}
void init()
{
    siz=0;
    newnode();
}
void Insert(char *s,int len)
{
    int p=0;
    for(int i=0;i<len;i++)
    {
        int &x=next[p][s[i]-tab];
        p=x?x:x=newnode();
    }
    num[p]++;
}

void acbuild()
{
    queue<int>Q;
    Q.push(0);
    while(!Q.empty())
    {
        int temp=Q.front();
        Q.pop();
        for(int i=0;i<max_next;i++)
        {
            int v=next[temp][i];
            if(v==0)next[temp][i]=next[fail[temp]][i];
            else Q.push(v);
            if(temp!=0)fail[v]=next[fail[temp]][i];
            if(num[next[fail[temp]][i]])num[next[temp][i]]++;
        }
    }
}
int vis[maxn];
bool dfs(int now)
{
    vis[now]=1;
    for(int j=0;j<max_next;j++)
    {
        if(num[next[now][j]])continue;
        if(vis[next[now][j]]==1)return true;
        if(vis[next[now][j]]==0 && dfs(next[now][j]))return true;
    }
    vis[now]=-1;
    return false;
}

char word[30005];
int main()
{
    int n,L;
    while(scanf("%d",&n)!=EOF)
    {
        init();
        for(int i=1;i<=n;i++)
        {
            scanf("%s",word);
            Insert(word,strlen(word));
        }
        acbuild();
        memset(vis,0,sizeof vis);
        bool ans=false;
        for(int i=0;i<siz;i++)
        if(!vis[i] && dfs(i))
        {
            ans=true;
            break;
        }
        acdebug();
        if(ans)puts("TAK\n");
        else puts("NIE\n");
    }
    return 0;
}
时间: 2024-10-03 08:22:16

Hnu 10104 病毒 (AC自动机+dfs)的相关文章

BZOJ 2434: [Noi2011]阿狸的打字机( AC自动机 + DFS序 + 树状数组 )

一个串a在b中出现, 那么a是b的某些前缀的后缀, 所以搞出AC自动机, 按fail反向建树, 然后查询(x, y)就是y的子树中有多少是x的前缀. 离线, 对AC自动机DFS一遍, 用dfs序+树状数组维护, DFS到的查询点就回答询问.时间复杂度O(|ACAM|+QlogQ) ------------------------------------------------------------------------------------------- #include<cstdio>

[NOI2011]阿狸的打字机 AC自动机+DFS序+树状数组

[NOI2011]阿狸的打字机 Description 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母.经阿狸研究发现,这个打字机是这样工作的: l 输入小写字母,打字机的一个凹槽中会加入这个字母(这个字母加在凹槽的最后).l 按一下印有'B'的按键,打字机凹槽中最后一个字母会消失.l 按一下印有'P'的按键,打字机会在纸上打印出凹槽中现有的所有字母并换行,但凹槽中的字母不会消失.例如,阿狸输入aPaPBbP

[NOI2011][bzoj2434] 阿狸的打字机 [AC自动机+dfs序+fail树+树状数组]

题面 传送门 正文 最暴力的 最暴力的方法:把所有询问代表的字符串跑一遍kmp然后输出 稍微优化一下:把所有询问保存起来,把模板串相同的合并,求出next然后匹配 但是这两种方法本质没有区别,都是暴力 不那么暴力的 我们对于所有的串建立一个AC自动机,把询问按照$y$排序,然后在AC自动机上面跑,每次跳fail更新答案 这样可以拿到70分,但是时间上限还是会$O\left(n^2\right)$左右 巧妙的优化 这道题里面,所有的模板串和文本串都在AC自动机里 那么,题目中实际是在要求什么呢?

CodeForces 547E:Mike and Friends(AC自动机+DFS序+主席树)

What-The-Fatherland is a strange country! All phone numbers there are strings consisting of lowercase English letters. What is double strange that a phone number can be associated with several bears! In that country there is a rock band called CF con

18.10.29 躲不开的病毒(AC自动机+dfs)

描述 有若干种病毒,每种病毒的特征代码都是一个01串. 每个程序也都是一个01串. 问是否存在不被病毒感染(不包含任何病毒的特征代码)的无限长的程序. 输入第一行是整数n,表示有n个病毒接下来n行,每行是一个由 0,1构成的字符串,表示一个病毒特征代码所有的病毒的特征代码总长度不超过30000输出如果存在无限长的没有被病毒感染的程序,输出 "TAK",否则输出"NIE" 样例输入 样例1: 2 10 11 样例2: 2 1 0 样例输出 样例1: TAK 样例2:

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

[COCI2015] Divljak - AC自动机,DFS序,树状数组,LCA

有 \(n\) 个询问串 \(S_i\),有一个初始为空的字符串集合 \(T\),接下来有 \(q\) 个操作,每次向集合中添加一个字符串,或给定 \(x\) 询问集合中有多少个字符串包含 \(S_x\) Solution 考虑对 \(S_i\) 建立 ACAM,建出 \(fail\) 树,一个点发生匹配,则需要修改它到根的链,询问就是查询一个点的值 这样需要树链剖分,我们可以差分一下,那么每次修改的就是一个点,询问的是一个子树的和 于是我们求出 \(fail\) 树的 DFS 序,用树状数组维

AC自动机- 自我总结

AC自动机算法总结  No.1 What's Aho-Corasick automaton? 一种多模式串匹配算法,该算法在1975年产生于贝尔实验室,是著名的多模匹配算法之一. 简单的说,KMP用来匹配一个模式串:但如果现在有多个模式串需要在同一篇文章中出现,现在就需要Aho-Corasick automaton算法了. 不要天真的以为AC自动机为auto-Accept,虽然他能让你AC一些题. No.2 My Understanding About Aho-Corasick automato

[日常摸鱼][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