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

    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自动机。
    想象一个无限长的安全代码存在,那么拿它到AC自动机上匹配,它会一直匹配但是一直匹配不成功。
    也就是说匹配的时候不能匹配到End为1的结点(设为x),且fail指针指向终点的点(设为y)也不能匹配到,因为root..x是root..y的一个后缀。
    而要无限长,即一直匹配,就说明在匹配过程中会遇上一个环。
    所以就是在AC自动机上看有没有环就行了。

    感觉每做一道AC自动机的题就重新学一遍AC自动机

    #include <bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int p=10007;
    const int N=1e6+10;
    const int M=5e5+10;
    int n,T;
    char s[N];
    struct acmach
    {
        int Next[M][2],Fail[M];
        bool End[M];
        bool vis[N],in[N];
        int root,L;
        int newnode()
        {
            for (int i=0;i<2;i++) Next[L][i]=-1;
            End[L]=0;
            return L++;
        }
        void init()
        {
            L=0;
            root=newnode();
            for (int i=0;i<N;i++) vis[i]=in[i]=0;
        }
        void Insert(char s[])
        {
            int len=strlen(s);
            int now=root;
            for (int i=0;i<len;i++)
            {
                if (Next[now][s[i]-'0']==-1)
                    Next[now][s[i]-'0']=newnode();
                now=Next[now][s[i]-'0'];
            }
            End[now]=1;
        }
        void build()
        {
            queue<int>q;
            Fail[root]=root;    
            for (int i=0;i<2;i++)
            if (Next[root][i]==-1) Next[root][i]=root; 
            else
            {
                Fail[Next[root][i]]=root;
                q.push(Next[root][i]);
            }
            while (!q.empty())
            {
                int now=q.front(); q.pop();
                End[now]|=End[Fail[now]];   //对于File指向End的点也不能访问到
                for (int i=0;i<2;i++)
                if (Next[now][i]==-1) Next[now][i]=Next[Fail[now]][i]; 
                else
                {
                    Fail[Next[now][i]]=Next[Fail[now]][i]; 
                    q.push(Next[now][i]);
                }
            }
        }
        bool dfs(int x)
        {
            in[x]=1;
            for (int i=0;i<2;i++)
            {
                int v=Next[x][i];
                if (in[v]) return 1;
                if (vis[v] || End[v]) continue;
                vis[v]=1;
                if (dfs(v)) return 1;
            }
            in[x]=0;
            return 0;
        }
    }ac;
    int main()
    {
        ac.init();
        scanf("%d",&n);
        for (int i=1;i<=n;i++)
        {
            scanf("%s",s);
            ac.Insert(s);
        }
        ac.build();
        if (ac.dfs(ac.root)) printf("TAK
    ");
        else printf("NIE
    ");
    
        return 0;
    }
    View Code
  • 相关阅读:
    AppCrawler自动化遍历使用详解(版本2.1.0 )
    python 接口测试1 --如何创建和打印日志文件
    通过Xshell登录远程服务器实时查看log日志
    java基础知识6-- 抽象类,抽象方法,接口,构造方法,类方法等易混淆的知识点
    java基础知识5--集合类(Set,List,Map)和迭代器Iterator的使用
    java基础知识4--数组的常用方法(Array)
    java基础知识3--如何获取资源文件(Java中获取资源文件的url)
    java基础知识2--String,StringBufffer,StringBuilder的区别
    java基础知识1--String常用方法总结
    javascript正则表达式验证密码(必须含数字字符特殊符号,长度4-16位之间)
  • 原文地址:https://www.cnblogs.com/tetew/p/11545214.html
Copyright © 2011-2022 走看看