bzoj2938 病毒

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自动机+判环。如果当匹配时存在环,说明存在,反之不行。
 
 
    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <cstdlib>
    #include <queue>
    #define MAXN 1000010
    #define REP(i,k,n) for(int i=k;i<=n;i++)
    #define in(a) a=read()
    using namespace std;
    inline int read(){
        int x=0,f=1;
        char ch=getchar();
        for(;!isdigit(ch);ch=getchar())
            if(ch=='-')
                f=-1;
        for(;isdigit(ch);ch=getchar())
            x=x*10+ch-'0';
        return f*x;
    }
    int n;
    queue <int> Q;
    char input[300010];
    int tree[300010][2],total=1,isend[300010];
    int vis[300010],nxt[300010],book[300010]; 
    inline void insert(char *s){
        int l=strlen(s);
        int u=1;
        REP(i,0,l-1){
            int c=s[i]-'0';
            if(!tree[u][c])  tree[u][c]=++total;
            u=tree[u][c];
        }
        isend[u]=1;
        return ;
    }
    inline void getnext(){
        tree[0][0]=tree[0][1]=1;
        nxt[1]=0;
        Q.push(1);
        while(!Q.empty()){
            int u=Q.front();
            Q.pop();
            REP(c,0,1){
                if(!tree[u][c])  tree[u][c]=tree[nxt[u]][c];
                else{
                    int k=nxt[u];
                    nxt[tree[u][c]]=tree[nxt[u]][c];
                    isend[tree[u][c]]=isend[tree[u][c]]|isend[tree[nxt[u]][c]];
                    Q.push(tree[u][c]);
                }
            }    
        }
        return ;
    }
    inline bool dfs(int x){
        vis[x]=1;
        for(int i=0;i<2;i++)
        {
            int v=tree[x][i];
            if(vis[v])return 1;
            if(book[v] || isend[v])
                continue;
            book[v]=1;
            if(dfs(v))return 1;
        }
        vis[x]=0;
        return 0;
    }
    int main(){
        in(n);
        REP(i,1,n){
            scanf("%s",input);
            insert(input);
        }
        getnext();
        if(dfs(1))  cout<<"TAK"<<endl;
        else  cout<<"NIE"<<endl;
        return 0;
    }

 

posted @ 2018-09-26 20:05  Dijkstra·Liu  阅读(263)  评论(0编辑  收藏  举报