嘘~ 正在从服务器偷取页面 . . .

洛谷P2444 [POI2000]病毒 题解


洛谷P2444 [POI2000]病毒 题解

题目链接:P2444 [POI2000]病毒

题意

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

示例:

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

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

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

不难发现这是一个 \(\tt{AC}\) 自动机的题目

考虑一个安全代码在 \(\tt{AC}\) 自动机上是怎么跑的

显然它会从 \(0\) 结点开始跑,然后最后在一个环上面跑

这个环显然不能包含「是字符串结尾的结点」

仔细想一想,其实不止这些结点!

对于一个结点 \(u\) ,如果它的 \(\tt{fail}\) 指针所指向的结点是「是字符串结尾的结点」

那么 \(u\) 也是不能走的我们称这些结点为 「含病毒后缀的结点」

当然,如果一个结点的 \(\tt{fail}\) 指针所指向的结点是「含病毒后缀的结点」,

那么这个结点也是「含病毒后缀的结点」,同样不可以走

说了这么多,其实只需要在板子上加一句

if(ed[fail[trie[u][i]]])++ed[trie[u][i]];

就好了

时间复杂度 \(O(\sum |s_i|)\)

代码:

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <iomanip>
#include <random>
#include <queue>
using namespace std;
// #define int long long
// #define INF 0x3f3f3f3f3f3f3f3f
#define N (int)(2e3+15)
#define L (int)(3e4+15)
struct Trie
{
    queue<int> q;
    int tot,trie[L][2],ed[L],fail[L];
    void insert(string s)
    {
        int u=0;
        for(int i=0; i<s.size(); i++)
        {
            int c=s[i]-'0';
            if(!trie[u][c])trie[u][c]=++tot;
            u=trie[u][c];
        }
        ++ed[u];
    }
    void build()
    {
        for(int i=0; i<2; i++)
            if(trie[0][i])q.push(trie[0][i]);
        while(!q.empty())
        {
            int u=q.front(); q.pop();
            for(int i=0; i<2; i++)
            {
                if(trie[u][i])
                {
                    fail[trie[u][i]]=trie[fail[u]][i];
                    if(ed[fail[trie[u][i]]])++ed[trie[u][i]];
                    q.push(trie[u][i]);
                }else trie[u][i]=trie[fail[u]][i];
            }
        }
    }
    int ins[L],vis[L];
    bool dfs(int u)
    {
        ins[u]=1;
        for(int i=0; i<2; i++)
        {
            int v=trie[u][i];
            if(ins[v])return 1;
            if(vis[v]||ed[v])continue;
            vis[v]=1; if(dfs(v))return 1;
        }
        ins[u]=0;
        return 0;
    }
    void solve()
    {
        for(int i=1; i<=tot; i++)
            ins[i]=vis[i]=0;
        vis[0]=1;
        cout << (dfs(0)?"TAK\n":"NIE\n");
    }
}tr;
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    // freopen("check.in","r",stdin);
    // freopen("check.out","w",stdout);
    int n; string s;
    cin >> n;
    for(int i=1; i<=n; i++)
    {
        cin >> s;
        tr.insert(s);
    }
    tr.build();tr.solve();
    return 0;
}

文章作者: q779
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 q779 !
评论
  目录