洛谷P2444 [POI2000]病毒
? 解题记录 ? ? 洛谷 ? ? AC自动机 ?    2018-06-24 23:00:06    606    0    0

题目描述

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

示例:

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

任务:

请写一个程序:

1.在文本文件WIR.IN中读入病毒代码;

2.判断是否存在一个无限长的安全代码;

3.将结果输出到文件WIR.OUT中。

输入输出格式

输入格式:

 

在文本文件WIR.IN的第一行包括一个整数n (n\le 2000)(n2000) ,表示病毒代码段的数目。以下的n行每一行都包括一个非空的01字符串——就是一个病毒代码段。所有病毒代码段的总长度不超过30000。

 

输出格式:

 

在文本文件WIR.OUT的第一行输出一个单词:

TAK——假如存在这样的代码;

NIE——如果不存在。

 

输入输出样例

输入样例#1: 复制
3
01 
11 
00000

输出样例#1: 复制

NIE​​

多串匹配问题首选AC自动机。不过这题是匹配不上,其他题是匹配得上。再想想就能发现只需要在AC自动机上走出一个环,不碰到所有表示匹配成功得状态得节点就是可以构造出来的。那么我们把AC自动机这样处理:对于一个点如果0,1的转移都是正常边就连原来的点,如果0,1没有转移那么就用AC自动机的匹配操作跳出失配后转到的节点连边。最后把匹配点标记找有没有环就行了。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
#include<stack>
using namespace std;
const int maxn = 4e6 + 5;
struct edge {
    int v, next;
}e[maxn << 1];
int head[maxn], cnt, dfn[maxn], vis[maxn];
void adde(const int &u, const int &v) {
    e[++cnt] = (edge) {v, head[u]};
    //cerr << u << "--->" << v << endl;
    head[u] = cnt;
}
char s[maxn], blk[maxn];
namespace AC {
    int trie[maxn][2], fa[maxn], cnt = 1;
    void insert(char * s) {
        int len = strlen(s), id, now = 1;
        for(register int i = 0; i < len; ++i) {
            id = s[i] - '0';
            if(trie[now][id]) now = trie[now][id];
            else now = trie[now][id] = ++cnt;
        }
        blk[now] = 1;
    }
    void create() {
        queue<int > q;
        q.push(1);
        while(!q.empty()) {
            int u = q.front(), v, p;
            q.pop();
            for(register int i = 0; i < 2; ++i) {
                if(!trie[u][i]) continue;
                v = trie[u][i], p = fa[u];
                while(p && !trie[p][i]) p = fa[p];
                if(p) fa[v] = trie[p][i];
                else fa[v] = 1;
                q.push(v), blk[v] |= blk[fa[v]];
            }
        }
    }
    void con() {
        queue<int > q;
        q.push(1);
        while(!q.empty()) {
            int u = q.front(), p;
            q.pop();
            for(register int i = 0; i < 2; ++i) {
            	p = fa[u];
                if(trie[u][i]) adde(u, trie[u][i]), q.push(trie[u][i]);
                else {
                    while(p && !trie[p][i]) p = fa[p];
                    if(p) adde(u, trie[p][i]);
                    else adde(u, 1);
                }
            }
        }
    }
}
int flag = 0;
void dfs(int u) {
    if(flag) return ;
    dfn[u] = 1, vis[u] = 1;
    //cerr << u << "--in" << endl;
    for(register int i = head[u]; i; i = e[i].next) {
        int v = e[i].v;
        if(blk[v]) continue;
        if(dfn[v]) {
            if(vis[v]) flag = 1;
            continue;
        }
        dfs(v);
    }
    vis[u] = 0;
}
int n;
int main() {
    scanf("%d", &n);
    while(n--) {
        scanf("%s", s);
        AC::insert(s);
    }
    AC::create();
    AC::con(), dfs(1);
    if(flag) printf("TAK");
    else printf("NIE");
    return 0;
}



上一篇: 洛谷P3592 [POI2015]MYJ

下一篇: 洛谷P3537 [POI2012]SZA-Cloakroom

606 人读过
立即登录, 发表评论.
没有帐号? 立即注册
0 条评论
文档导航