zoukankan      html  css  js  c++  java
  • P2444 [POI2000]病毒

    P2444 [POI2000]病毒

    题目描述

    二进制病毒审查委员会最近发现了如下的规律:某些确定的二进制串是病毒的代码。如果某段代码中不存在任何一段病毒代码,那么我们就称这段代码是安全的。现在委员会已经找出了所有的病毒代码段,试问,是否存在一个无限长的安全的二进制代码。

    示例:

    例如如果{011, 11, 00000}为病毒代码段,那么一个可能的无限长安全代码就是010101…。如果{01, 11, 000000}为病毒代码段,那么就不存在一个无限长的安全代码。

    任务:

    请写一个程序:

    1.在文本文件WIR.IN中读入病毒代码;

    2.判断是否存在一个无限长的安全代码;

    3.将结果输出到文件WIR.OUT中。

    输入输出格式

    输入格式:

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

    输出格式:

    在文本文件WIR.OUT的第一行输出一个单词:

    TAK——假如存在这样的代码;

    NIE——如果不存在。

    输入输出样例

    输入样例#1: 
    3
    01 
    11 
    00000
    
    输出样例#1: 
    NIE

    这是一道非常有意思的AC自动机题目,首先我们可以根据读入的模式串把trie树给建好,然后把next数组搞出来,然后就GG了,这也没个文本串啊,这咋办啊?既然正着想不好办,我们可以考虑反过来想,如果有这样的一个字符串满足题目的要求不含有病毒代码,那么把这个字符串在trie树上跑回咋样呢?对啦,这个文本串一定不可以与任何一个模式串成功匹配,也就是说这个文本串会在trie树上跳来跳去,那么我们一定可以在trie树上找到一个环使得这个文本串会在这个环里来回跳。

    看下面这个例子:

    3

    011

    11

    00000我们先把trie树建好,把next数组构造好,然后我们把文本串010101…跑一遍AC自动机,会发生什么呢?


    不难看出,这个文本串会在上图中的0、1两个结点中来回跳,而且不能和任何一个模式串完全匹配。这样问题也就转化为了能否在trie树上利用next数组找到一个环使得这个环上不含有模式串的结束结点。看上去我们直接把所有模式串的结束结点打上标记然后直接dfs找环不就行了?貌似没有什么问题,但是这样做并不正确。

    看下面的例子:

    3

    00

    1

    0100

    我们继续把trie树和next数组给搞出来,然后进行dfs找环,但是这样会发生什么呢?我们会沿着上图中蓝色箭头所指的线路走,这样就会错误的判断为这个trie树上有环,但是显然这个树上是不存在环的,那么问题出在哪里呢?

    对了,就是这个结点,根据next数组的含义,我们不难发现,只要这个结点的next链上含有模式串的结束结点,那么我们也应当把这个点打上模式串的结束标记,所以,我们还要把next链上存在模式串结束结点的点打上标记,这样就没有问题了。

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cmath>
      4 #include<string>
      5 #include<cstring>
      6 #include<map>
      7 #include<queue>
      8 #include<stack>
      9 #include<algorithm>
     10 #include<vector>
     11 #define maxn 60005
     12 using namespace std;
     13 
     14 inline int read()
     15 {
     16     char c=getchar();
     17     int res=0,x=1;
     18     while(c<'0'||c>'9')
     19     {
     20         if(c=='-')
     21         x=-1;
     22         c=getchar();
     23     }
     24     while(c>='0'&&c<='9')
     25     {
     26         res=res*10+(c-'0');
     27         c=getchar();
     28     }
     29     return res*x;
     30 }
     31 
     32 int n,tot=1,pd;
     33 int tree[maxn][15],nt[maxn],bo[maxn],dfn[maxn],vis[maxn];
     34 char a[maxn];
     35 queue<int>q;
     36 
     37 void trie(char *s)
     38 {
     39     int len=strlen(s),u=1;
     40     for(register int i=0;i<len;i++)
     41     {
     42         int c=s[i]-'0';
     43         if(!tree[u][c])
     44         {
     45             tree[u][c]=++tot;
     46         }
     47         u=tree[u][c];
     48     }
     49     bo[u]=1;
     50 }
     51 
     52 void bfs()
     53 {
     54     for(register int i=0;i<10;i++)
     55     {
     56         tree[0][i]=1;
     57     }
     58     nt[1]=0;q.push(1);
     59     while(q.size())
     60     {
     61         int u=q.front();q.pop();
     62         for(register int i=0;i<10;i++)
     63         {
     64             if(!tree[u][i])
     65             tree[u][i]=tree[nt[u]][i];
     66             else
     67             {
     68                 int v=tree[u][i];
     69                 q.push(v);
     70                 nt[v]=tree[nt[u]][i];
     71             }
     72         }
     73     }
     74 }
     75 
     76 void dfs(int x)
     77 {
     78     if(pd) return;
     79     for(int i=0;i<=1;i++)
     80     {
     81         if(!vis[tree[x][i]]&&!bo[tree[x][i]])
     82         {
     83             vis[tree[x][i]]=1;
     84             dfs(tree[x][i]);
     85             vis[tree[x][i]]=0;
     86         }
     87         else if(!bo[tree[x][i]]&&vis[tree[x][i]])
     88         {
     89             pd=1;
     90             return;
     91         }
     92     }
     93 }
     94 
     95 int main()
     96 {
     97     n=read();
     98     for(register int i=1;i<=n;i++)
     99     {
    100         scanf("%s",a);
    101         trie(a);
    102     }
    103     bfs();
    104     vis[1]=1;
    105     for(int i=2;i<=tot;i++)
    106     {
    107         int k=i,m=0;
    108         while(k>1)
    109         {
    110             if(bo[k])
    111             m=k;
    112             k=nt[k];
    113         }
    114         k=i;
    115         if(m==0) continue;
    116         while(k>1)
    117         {
    118             if(k==m) break;
    119             bo[k]=1;
    120             k=nt[k];
    121         }
    122     }
    123     dfs(1);
    124     if(pd)
    125     {
    126         printf("TAK
    ");
    127     }
    128     else
    129     {
    130         puts("NIE");
    131     }
    132     return 0;
    133 }
    View Code
  • 相关阅读:
    Cleve Moler MATLAB 创始人金秋10月中国大学校园行
    [原]ASP.NET中使用JQUERYEASYUI后,解决ClientScript.RegisterStartupScript 所注册脚本执行两次
    [原]ASP.NET中使用后端代码注册脚本 生成JQUERYEASYUI 的界面错位
    [原]jqueryeasyui 关闭tab如何自动切换到前一个tab
    [原创]C# 实例Oracle 备份,带进度提示
    停止Oracle 服务开机自动重启
    最新县及县以上行政区划代码(截止2009年12月31日)
    单元测试学习:无返回值,触发委托
    [笔记]GetRequestStream()超时问题(出现假死,卡住)
    asp.net 页面 css中图片不存在引发的异常
  • 原文地址:https://www.cnblogs.com/snowy2002/p/10695615.html
Copyright © 2011-2022 走看看