LGP2444 病毒 (AC自动机)

LGP2444 病毒

Mean

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

示例:

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

现在给出所有的病毒代码段,判断是否存在无限长的安全代码。

\(1≤n≤2000\),所有病毒代码段的总长度不超过 \(3 \times 10^4\)

Sol

AC自动机

将所有串插入\(trie\),并记录终止节点。

若一个节点\(x\)\(fail\)链上有一个终止节点,则其为非法点,因为若走到这个点这意味着一定会出现病毒。

在求\(fail\)的过程中同时求出\(vis[x]\),表示节点\(x\)\(fail\)链上有至少一个终止节点。

那么若存在安全代码,当且仅当存在一个从\(0\)点开始出发,不经过非法点的环。

直接\(dfs\)即可,一有环直接返回。

Code

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define dep(i,a,b) for(int i=(a);i>=(b);--i)
#define lowbit(x) (x&(-x))
#define debug(x) cout<<#x<<" :"<<x<<endl
#define debug1(x) cout<<#x<<" :"<<x<<" "
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int N=2e5+20;
const int MAX=10000007;
inline int read() {
    char c=getchar();int x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0',c=getchar();}
    return x*f;
}

inline void out(int x) {   
    if(x>9) out(x/10);   
    putchar(x%10+'0'); 
}     
int q[N];
int n;
int tr[N][2];
int cnt[N];
int vis[N];
int fail[N];
char s[N];
int tot;
void insert(int id){
    int p=0;
    for(int i=1;s[i];++i){
        int v=s[i]-'0';
        if(!tr[p][v])tr[p][v]=++tot;
        p=tr[p][v];
    }
    vis[p]=1;
}
void build(){
    queue<int>Q;
    for(int i=0;i<2;++i){
        if(tr[0][i])Q.push(tr[0][i]);
    }
    while(!Q.empty()){
        int k = Q.front();
        Q.pop();
        for(int i=0;i<2;++i){
            if(tr[k][i]){
                fail[tr[k][i]]=tr[fail[k]][i];
                Q.push(tr[k][i]);
                vis[tr[k][i]]|=vis[fail[tr[k][i]]];
            }
            else{
                tr[k][i]=tr[fail[k]][i];
            }
        }
    }
}
int flag=0;
int dfs(int x){
    if(cnt[x]==1){
        return 1;
    }
    cnt[x]=1;
    for(int i=0;i<2;++i){
        if(vis[tr[x][i]]==0){
            flag|=dfs(tr[x][i]);
        }
        if(flag)return 1;
    }
    cnt[x]=0;
    return 0;
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;++i){
        scanf("%s",s+1);
        insert(i);
    }
    build();

    dfs(0);
    if(flag)puts("TAK");
    else puts("NIE");
    return 0;
}             
 
posted @ 2021-10-18 16:34  Qquun  阅读(153)  评论(0)    收藏  举报