zoukankan      html  css  js  c++  java
  • bzoj 2938 [Poi2000]病毒 AC自动机

     [Poi2000]病毒

    Time Limit: 1 Sec  Memory Limit: 128 MB
    Submit: 1319  Solved: 659
    [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的一个后缀

    处理出来判断有向图是否有环

     1 #include<cstring>
     2 #include<iostream>
     3 #include<algorithm>
     4 #include<cmath>
     5 #include<cstdio>
     6 #include<queue>
     7 
     8 #define N 30007
     9 using namespace std;
    10 inline int read()
    11 {
    12     int x=0,f=1;char ch=getchar();
    13     while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    14     while(isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    15     return x*f;
    16 }
    17 
    18 int n,m,cnt=1;
    19 bool flag[N],ans,ins[N];
    20 struct Node
    21 {
    22     int c[2],suf;
    23     bool flag;
    24 }trie[N];
    25 char ch[N];
    26 
    27 void insert()
    28 {
    29     int now=1,len=strlen(ch);
    30     for (int i=0;i<len;i++)
    31     {
    32         if (!trie[now].c[ch[i]-'0']) trie[now].c[ch[i]-'0']=++cnt;
    33         now=trie[now].c[ch[i]-'0'];
    34     }
    35     trie[now].flag=true;
    36 }
    37 void make_AC()
    38 {
    39     for (int i=0;i<2;i++)
    40         trie[0].c[i]=1;
    41     queue<int>q;while(!q.empty()) q.pop();
    42     trie[1].suf=0;
    43     q.push(1);
    44     while(!q.empty())
    45     {
    46         int u=q.front();q.pop();
    47         for (int i=0;i<2;i++)
    48             if (trie[u].c[i])
    49             {
    50                 trie[trie[u].c[i]].suf=trie[trie[u].suf].c[i];
    51                 if (trie[trie[trie[u].c[i]].suf].flag) trie[trie[u].c[i]].flag=true;
    52                 q.push(trie[u].c[i]);
    53             }
    54             else trie[u].c[i]=trie[trie[u].suf].c[i];
    55     }
    56 }
    57 void dfs(int u)
    58 {
    59     ins[u]=true;
    60     for (int i=0;i<2;i++)
    61     {
    62         int v=trie[u].c[i];
    63         if (ins[v]) ans=true;
    64         if (trie[v].flag||flag[v]) continue;
    65         flag[v]=true;
    66         dfs(v);
    67     }
    68     ins[u]=false;
    69 }
    70 int main()
    71 {
    72     n=read();
    73     for (int i=1;i<=n;i++)
    74     {
    75         scanf("%s",ch);
    76         insert();
    77     }
    78     make_AC(),dfs(1);
    79     if (ans) printf("TAK
    ");
    80     else printf("NIE
    ");
    81 }
  • 相关阅读:
    C# IEnumerable 和 IEnumerator接口浅析
    SQLite笔记
    命令行工具osql.exe使用
    2016年年终工作总结
    c# Json 自定义类作为字典键时,序列化和反序列化的处理方法
    多线程随笔
    常见异步机制分析
    SQL 通过syscolumns.xtype动态查找指定数据类型字段所包含的数据
    SQL 删除索引错误
    SQL 实用函数
  • 原文地址:https://www.cnblogs.com/fengzhiyuan/p/8847776.html
Copyright © 2011-2022 走看看