BZOJ 2938: [Poi2000]病毒 ACAM

title

BZOJ 2938

LUOGU 24444

简化题意:

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

示例:

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

任务:

请写一个程序:

  1. 读入病毒代码;
  2. 判断是否存在一个无限长的安全代码;
  3. 将结果输出。

analysis

如果直接构造该串的话,时间复杂度显然会爆炸。

考虑AC自动机上该串匹配的性质。

很明显在AC自动机上,这个无限长的字符串永远不会到达一个标记节点,只会在AC自动机上的一个环上不断匹配。

所以我们只要找到这个环就行了。

注意如果一个节点的 \(fail\) 节点如果是标记节点,那么它自身也是标记节点,因为该节点的 \(fail\) 节点到根节点的串是该节点到根节点的串的后缀。

code

#include<bits/stdc++.h>

const int maxn=3e4+10;

namespace IO
{
    char buf[1<<15],*fs,*ft;
    inline char getc() { return (ft==fs&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),ft==fs))?0:*fs++; }
    template<typename T>inline void read(T &x)
    {
        x=0;
        T f=1, ch=getchar();
        while (!isdigit(ch) && ch^'-') ch=getchar();
        if (ch=='-') f=-1, ch=getchar();
        while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
        x*=f;
    }
}

using IO::read;

struct Aho_Corasick_AutoMaton
{
    int son[maxn][2],fail[maxn],cnt;
    bool v[maxn];
    inline void add(char *s)
    {
        int len=strlen(s+1), now=0;
        for (int i=1; i<=len; ++i)
        {
            int c=s[i]-'0';
            if (!son[now][c]) son[now][c]=++cnt;
            now=son[now][c];
        }
        v[now]=true;
    }

    inline void build()
    {
        std::queue<int>q;
        for (int i=0; i<2; ++i)
            if (son[0][i]) q.push(son[0][i]);
        while (!q.empty())
        {
            int x=q.front();
            q.pop();
            for (int i=0; i<2; ++i)
                if (son[x][i]) fail[son[x][i]]=son[fail[x]][i], v[son[x][i]]|=v[fail[son[x][i]]], q.push(son[x][i]);
                else son[x][i]=son[fail[x]][i];
        }
    }
} ACAM;

bool vis[maxn],ins[maxn];
inline void dfs(int x)
{
    if (ins[x]) { puts("TAK"); exit(0); }
    if (vis[x] || ACAM.v[x]) return ;
    vis[x]=ins[x]=1;
    if (ACAM.son[x][0]) dfs(ACAM.son[x][0]);
    if (ACAM.son[x][1]) dfs(ACAM.son[x][1]);
    ins[x]=0;
}

char ch[maxn];
int main()
{
    int n;read(n);
    for (int i=1; i<=n; ++i) scanf("%s",ch+1), ACAM.add(ch);
    ACAM.build();
    dfs(0);
    puts("NIE");
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/G-hsm/p/11429544.html