POI2000 病毒

不禁令人想起

洛天依吸毒,好像是吸了熊猫烧香

正常的部分

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

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

任务:
请写一个程序:
1.在文本文件WIR.IN中读入病毒代码;
2.判断是否存在一个无限长的安全代码,存在输出TAK,否则输出NIE;
Ps.luogu上输TAK有五十五分

其实和AC自动机并没多大关系,然而它就是这类。
让我们脑补一下,如果存在这个无限串,那么在对病毒库进行匹配的时候,我们的指针会在AC机上绕圈:
这里写图片描述
我们把失配边(就是fail)、Trie的边认作单向边。顺着之前的思路,如果能够从root走出一个环(环上不能有end节点),则存在这样的串。

另外,如果一个模板串中存在一个危险字串,也就是某个位置fail指针指向一个end节点,那么它之后的节点也都是危险节点:
这里写图片描述
(危险节点已用红色框出

入坑找环的办法:

从根节点开始DFS,不经过危险节点。来到一个新节点时,将新节点入栈并标记,然后接着DFS,直到回到一个在栈中的节点,也就是构成了环。注意,我们不能路过已经到过,但是不在栈中的点,否则环的相接处会出现“病毒”

然后。。。。
上代码:

#include<cstdio>
#include<string>
#include<algorithm>
#include<cstdlib>
#define maxn 33333

using namespace std;

int n,cnt=0,now=0;
short t[maxn][2],q[maxn],f[maxn],v,hed,til;
bool flg[maxn],vis[maxn],in[maxn];
char s[355];

void DFS(int x)
{
    if(in[x])   
        printf("TAK"),exit(0);
    if(vis[x]||flg[x])
        return;
    vis[x]=in[x]=1;
    DFS(t[x][0]);
    DFS(t[x][1]);
    in[x]=0;
}

int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;++i)
    {
        scanf("%s",s);
        now=0;
        for(int j=0;s[j];++j)
        {
            if(!t[now][s[j]-'0'])
                t[now][s[j]-'0']=++cnt;
            now=t[now][s[j]-'0'];
        }
        flg[now]=1;
    }
    if(t[0][0])
        q[++til]=t[0][0];
    if(t[0][1])
        q[++til]=t[0][1];
    while(hed^til)
    {
        now=q[++hed];
        for(int i=0;i<2;++i)
        {
            if(v=t[now][i])
                f[q[++til]=v]=t[f[now]][i],flg[v]|=flg[f[v]];
            else
                t[now][i]=t[f[now]][i];
        }
    }
    DFS(0);
    printf("NIE");
    return 0;
}

另一份很装X的代码(可惜WA俩点)

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<cstdlib>

using namespace std;

int n,cnt=0;
char s[2005][355];

class Trie
{
public:
    Trie *nxt[2],*f;
    int flg;
    bool in,vis;
    Trie()
    {
        nxt[0]=nxt[1]=f=NULL;
        flg=0;
        in=vis=false;
    }
}root,*now;

inline int read()
{
    char ch=getchar();int ret=0,f=1;
    while(ch>'9'||ch<'0'){if(ch=='-')f=-f;ch=getchar();}
    while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar();
    return ret*f;
}

void ACA()
{
    queue<Trie*>que;
    if(root.nxt[1])
    {
        que.push(root.nxt[1]);
        root.nxt[1]->f=&root;
    }
    if(root.nxt[0])
    {
        que.push(root.nxt[0]);
        root.nxt[0]->f=&root;
    }
    while(!que.empty())
    {
        Trie *hed=que.front();
        que.pop();
        for(int i=0;i<2;++i)
        {
            if(!hed->nxt[i])
            {
                hed->nxt[i]=hed->f->nxt[i];
                if(!hed->nxt[i])
                    hed->nxt[i]=&root;
                continue;
            }
            now=hed->f;
            que.push(hed->nxt[i]);
            Trie *u=hed->nxt[i];
            while(now&&!now->nxt[i])
                now=now->f;
            if(!now)
            {
                u->f=root.nxt[i];
                if(!u->f)
                    u->f=&root;
            }
            else
            {
                u->f=now->nxt[i];
                if(!u->f)
                    u->f=&root;
            }
            if(u->f->flg<0)
                u->flg=-(u->flg);
        }
    }
}

void DFS(Trie *now)
{
    if(now->in)
        puts("TAK"),exit(0);
    if(now->flg<0||now->vis)
        return;
    now->vis=now->in=true;
    if(now->nxt[0])
        DFS(now->nxt[0]);
    else
        DFS(&root);
    if(now->nxt[1])
        DFS(now->nxt[1]);
    else
        DFS(&root);
    now->in=false;
}

int main()
{
    n=read();
    root.f=&root;
    for(int i=1;i<=n;++i)
    {
        scanf("%s",s[i]);
        now=&root;
        for(int j=0;s[i][j];++j)
        {
            if(!now->nxt[s[i][j]-'0'])
                now->nxt[s[i][j]-'0']=new Trie;
            now=now->nxt[s[i][j]-'0'];
            if(!now->flg)
                now->flg=++cnt;
        }
        now->flg=-(now->flg);
    }
    ACA();
    DFS(&root);
    puts("NIE");
    return 0;
}
写在后面

好了今天我不想写这块内容。
转载不用注明出处,不会有人转的。

猜你喜欢

转载自blog.csdn.net/ZJ_0413_2017/article/details/80382194