• bzoj 2938: [Poi2000]病毒


    2938: [Poi2000]病毒

    Time Limit: 1 Sec  Memory Limit: 128 MB
    Submit: 1111  Solved: 556
    [Submit][Status][Discuss]

    Description

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

    Input

     
    第一行包括一个整数n,表示病毒代码段的数目。以下的n行每一行都包括一个非空的01字符串——就是一个病毒代码段。所有病毒代码段的总长度不超过30000。

    Output

    你应在在文本文件WIN.OUT的第一行输出一个单词:
    l         TAK——假如存在这样的代码;
    l         NIE——如果不存在。

    Sample Input

    3
    01
    11
    00000

    Sample Output

    NIE
    /*
        首先我们把所有串建一个AC自动机
        方便起见我们直接把fail指针合并到子结点
        如果一个串能无限长,也就是说它可以在AC自动机上一直进行匹配但就是匹配不上
        也就是说匹配指针不能走到val为1的结点,设这个点为x
        即root..x是一个病毒串
        那么fail指针指向x的y也不能走
        因为root..x是root..y的一个后缀
        处理出来判断有向图是否有环
        dfs即可
    */
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    using namespace std;
    #define maxn 30010
    int n,sz=1,a[maxn][2],fail[maxn],word[maxn];
    bool ins[maxn],vis[maxn];
    char s[maxn];
    void insert(){
        int now=1,len=strlen(s);
        for(int i=0;i<len;i++){
            int t=s[i]-'0';
            if(!a[now][t])a[now][t]=++sz;
            now=a[now][t];
        }
        word[now]=1;
    }
    void acmach(){
        queue<int>q;
        q.push(1);fail[1]=0;
        while(!q.empty()){
            int now=q.front();q.pop();
            for(int i=0;i<2;i++){
                if(!a[now][i]){a[now][i]=a[fail[now]][i];continue;}
                          int k=fail[now];
                while(!a[k][i])k=fail[k];
                fail[a[now][i]]=a[k][i];
                word[a[now][i]]|=word[a[k][i]];
                q.push(a[now][i]);
            }
        }
    }
    bool dfs(int x){//判断是否有环 
        ins[x]=1;
        for(int i=0;i<2;i++){
            if(ins[a[x][i]])return 1;
            if(vis[a[x][i]]||word[a[x][i]])continue;
            vis[a[x][i]]=1;
            if(dfs(a[x][i]))return 1;
        }
        ins[x]=0;
        return 0;
    }
    int main(){
        for(int i=0;i<2;i++)a[0][i]=1;
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            scanf("%s",s);
            insert();
        }
        acmach();
        if(dfs(1))printf("TAK");
        else printf("NIE");
        return 0;
    }
  • 相关阅读:
    一年来把自己从学.Net到用.Net,收集的资料共享出来B/s中的存储过程(二)
    收集的.Net文章(十五)ASP.NET 2.0 Caching For performance
    收集的.Net文章(十六)SQL Server日期计算
    P.V操作原语和信号量
    2004年2008年系分论文题目整理,考SA的可以看一下
    2010年个人总结
    MASM,NASM和AT&T汇编格式备注
    Unity Application Block 学习笔记之一使用配置文件
    Javascript 学习笔记之String类测试
    javascript学习笔记之Object类型测试
  • 原文地址:https://www.cnblogs.com/thmyl/p/8094022.html
Copyright © 2020-2023  润新知