• [Poi2000] 病毒


    2938: [Poi2000]病毒

    Time Limit: 1 Sec  Memory Limit: 128 MB
    Submit: 1633  Solved: 835
    [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

    HINT

    题意:

    给你$n$个01串,问是否存在一个无限长的串使得这$n$个串都不是它的子串。

     

    题解:

    建立$AC$自动机,那么若满足题意当且仅当在$AC$自动机上存在一个环不经过任意一个$end$节点,$dfs$找环即可。

    找环时注意:(对所有图论问题均有)

    • 存在环的条件不仅是$u ightarrow v$中的$v$被遍历过,它还要在当前遍历序列中!(主要是我又一次忘了把$vis_u$标记清0)
    • 若当前$u$的出边被遍历完并且没有找到环,说明$u$一定不在任何一个环上(反证),所以可以直接把它$delete$掉。

     

    代码:

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<queue>
    
    using namespace std;
    #define MAXN 100005
    #define MAXM 500005
    #define ll long long
    
    struct node{
        int son[2];
        bool ise,vis,ok;
    }tree[MAXN];
    int tot=1,nxt[MAXN];
    bool flag;char str[MAXN];
    inline int read(){
        int x=0,f=1;
        char c=getchar();
        for(;!isdigit(c);c=getchar())
            if(c=='-')
                f=-1;
        for(;isdigit(c);c=getchar())
            x=x*10+c-'0';
        return x*f;
    }
    
    inline void add(char *str){
        int N=strlen(str),u=1;
        for(int i=0;i<N;i++){
            int ch=str[i]-'0';
            if(!tree[u].son[ch]) 
                tree[u].son[ch]=++tot;
            u=tree[u].son[ch];
        }
        tree[u].ise=1;
        return;    
    }
    
    inline void get_nxt(){
        for(int i=0;i<2;i++)
            tree[0].son[i]=1;
        queue<int> q; q.push(1);
        while(!q.empty()){
            int u=q.front();q.pop();
            for(int i=0;i<2;i++){
                if(tree[u].son[i]){
                    q.push(tree[u].son[i]);
                    nxt[tree[u].son[i]]=tree[nxt[u]].son[i];
                    tree[tree[u].son[i]].ise|=tree[nxt[tree[u].son[i]]].ise;
                }
                else tree[u].son[i]=tree[nxt[u]].son[i];
            }
        }
        return;
    }
    
    inline int dfs(int u){
        tree[u].vis=tree[u].ok=1;
        for(int i=0;i<2;i++){
            int v=tree[u].son[i];
            if(tree[v].vis || (!tree[v].ok && !tree[v].ise && dfs(v)))
                return 1;
        }
        tree[u].vis=0;
        return 0;
    }
    
    int main(){
        int N=read();
        for(int i=1;i<=N;i++)
            scanf("%s",str),add(str);
        get_nxt();
        if(dfs(1)) printf("TAK
    ");
        else printf("NIE
    ");
         return 0;
    }

     

  • 相关阅读:
    第七章之main函数和启动例程
    第一章之系统调用、库函数、内核函数区别
    unp第七章补充之socket tcp 产生 rst响应的情况
    unp第七章补充之TCP半开连接与半闭连接
    Qt 布局管理器
    Qt setMargin()和setSpacing() 的含义
    工作感悟
    关于数组数据常用的技巧
    正则表达式练习
    call/apply应用-对象使用原型链上的方法
  • 原文地址:https://www.cnblogs.com/YSFAC/p/9839182.html
Copyright © 2020-2023  润新知