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 }
  • 相关阅读:
    Delphi XE5 android 蓝牙通讯传输
    Delphi XE5 android toast
    Delphi XE5 android openurl(转)
    Delphi XE5 如何设计并使用FireMonkeyStyle(转)
    Delphi XE5 android 捕获几个事件
    Delphi XE5 android listview
    Delphi XE5 android 黑屏的临时解决办法
    Delphi XE5 android popumenu
    Delphi XE5 android 获取网络状态
    Delphi XE5 android 获取电池电量
  • 原文地址:https://www.cnblogs.com/fengzhiyuan/p/8847776.html
Copyright © 2011-2022 走看看