zoukankan      html  css  js  c++  java
  • Poi2000病毒

    zz://https://www.cnblogs.com/Miracevin/p/9710746.html

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

    示例:

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

    输入格式:

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

    输出格式:

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

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

    NIE——如果不存在。

    题解:

    总长度不超过30000启发我们用trie,多个模式串匹配,启发我们用AC自动机。

    但是,一般的问题是,构造一个给定长度的串,使得出现若干个模式串等问题。

    通常用dp解决。

    但是这个题就比较新奇了。

    问你能不能构造一个无限长的串,不存在一个模式串。

    怎么处理无限问题?

    那么一定要考虑,为什么是无限的?

    也许有个循环节?可以考虑

    也可以反过来,考虑,如果我们把这个无限长的串,放在AC自动机上匹配,

    那么,最终的结果是,一定存在一个无限长的串,通过跳fail,可以在AC自动机上不断循环在一个环上。

    证明:

    我们把儿子指针作为一个向下的有向边,fail指针作为一个返祖边或者横叉边

    记AC自动机上的点代表的子串包含一个病毒代码的点称为危险点。

    对于AC自动机有环的情况,一定可以构造一个无限长的串。(先匹配到这个点,然后环上循环即可。)

    对于没有环的情况,匹配时一个节点一定只会经过一次。否则就有环了。

    那么,匹配下去,由于串无限长,节点有限个,那么必然会经过一个危险点,无解。

    证毕。

    所以, AC自动机建好后,类似Tarjan判环(强连通分量)即可。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N=2002;
    const int M=30000+5;
    struct AC{
        int ch[M][2],cnt;
        int fail[M];
        bool has[M];
        void ins(char *s){
            int len=strlen(s+1);
            int now=0;
            for(int i=1;i<=len;i++){
                int x=s[i]-'0';
                if(!ch[now][x]) ch[now][x]=++cnt;
                now=ch[now][x];
            }
            has[now]=1;
        }
        void build(){
            queue<int>q;
            for(int i=0;i<=1;i++) 
    		if(ch[0][i]) 
    		fail[ch[0][i]]=0,q.push(ch[0][i]);
            while(!q.empty())
    		{
                int x=q.front();q.pop();
                has[x]|=has[fail[x]];
                for(int i=0;i<=1;i++)
    			{
                    if(ch[x][i]){
                        fail[ch[x][i]]=ch[fail[x]][i];
                        q.push(ch[x][i]);
                    }
                    else ch[x][i]=ch[fail[x]][i];
                }
            }
        }
    }t;
    int n;
    char s[M];
    int dfn[M],low[M],df;
    int sta[M],top;
    bool in[M];
    bool fl;
    void dfs(int x){
        if(fl) return;
        dfn[x]=low[x]=++df;
        sta[++top]=x;
        in[x]=1;
        for(int i=0;i<=1;i++)
    	{
            if(t.has[t.ch[x][i]]) continue;
            if(!dfn[t.ch[x][i]])
    		{
                dfs(t.ch[x][i]);
                low[x]=min(low[x],low[t.ch[x][i]]);
            }
            else 
    		if(in[t.ch[x][i]]) 
    		   low[x]=min(low[x],dfn[t.ch[x][i]]);
        }
        if(low[x]==dfn[x])
    	{
            int sz=0;
            int z;
            do{
                z=sta[top--];
                sz++;
                in[z]=0;
            }while(z!=x);
            if(sz>1) fl=true;
        }
    }
    int main(){
        scanf("%d",&n);
        fl=false;
        for(int i=1;i<=n;i++){
            scanf("%s",s+1);
            t.ins(s);
        }
        t.build();
        dfs(0);
        puts(fl?"TAK":"NIE");
        return 0;
    }
    

      

  • 相关阅读:
    如何创建多线程
    Oracle导入数据表
    Oracle如何创建数据库用户
    Oracle忘记密码,如何修改密码
    Oracle如何创建表空间
    leetcode 787. K 站中转内最便宜的航班 js题解
    JS实现平衡二叉树
    typescript的安装与配置
    二分查找JS实现
    JS作用域(一):一般变量声明
  • 原文地址:https://www.cnblogs.com/cutemush/p/12268316.html
Copyright © 2011-2022 走看看