• [POI2000] 病毒


    题目类型:AC自动机

    传送门:>Here<

    题意:给出(N)(01)字符串,称为病毒串。问是否存在一个无限长的(01)(T),使得其中不包含任何一个病毒串

    解题思路

    如果我们拿(T)串去进行匹配会发生什么?

    考虑(AC)自动机匹配的条件:匹配时能够到达一个单词的结尾。因此找到(T)串的条件就是(T)串在匹配时永远不会到达一个单词的结尾,而是不停的能够在那些非结尾的点上绕圈

    因此我们先构建(Trie)树和(Fail)指针,然后在(AC)自动机上找环。

    特别注意(AC)自动机是有向图,所以不能简简单单的(DFS)看看有没有重复访问的。有关图的(DFS)问题无论如何,一定要先想到(DFS)树。在无向图中,一条边不是树边就是后向边,而后向边也就是有一端已经访问过了。所以只需要简单的判断是否访问即可。而由于有向图是单向边,所以还会存在横叉边和前向边。但横叉边和前向边都不可能形成环,因此我们的任务还是寻找后向边。后向边的找法很简单,可以维护一个栈,栈内保留从当前节点一直到(DFS)树根的所有节点,如果这条边所到达的点在栈内也就找到了后向边。

    另外我们在(DFS)的过程中不能走那些不能碰到的点,例如结尾节点。不妨称之为危险节点。

    危险节点真的只是结尾节点吗?我们之前在做(AC)自动机的时候,如果发现一个能匹配的结尾节点,还需要沿着(Fail)走统计后缀。例如两个字符串(S_1=101)(S_2=1010).两个串的结尾肯定都是危险节点,但是我们发现(S_1)(S_2)的前缀,如果(S_2)能够匹配(S_1)一定也能够匹配。因此(S_2)中的倒数第二个字符(1)也是危险节点!这个点也是不能走的!考虑前后缀的特性,我们能够得出结论:如果(u)是结尾节点,则(fail[u])就是危险节点

    Code

    /*By DennyQi 2018.8.21*/
    #include <cstdio>
    #include <queue>
    #include <cstdlib>
    #include <cstring>
    #include <algorithm>
    #define  r  read()
    #define  Max(a,b)  (((a)>(b)) ? (a) : (b))
    #define  Min(a,b)  (((a)<(b)) ? (a) : (b))
    using namespace std;
    typedef long long ll;
    const int MAXN = 10010;
    const int MAXM = 27010;
    const int INF = 1061109567;
    inline int read(){
        int x = 0; int w = 1; register int c = getchar();
        while(c ^ '-' && (c < '0' || c > '9')) c = getchar();
        if(c == '-') w = -1, c = getchar();
        while(c >= '0' && c <= '9') x = (x<<3) + (x<<1) + c - '0', c = getchar(); return x * w;
    }
    int N;
    char s[30010];
    int vis[30010],insta[30010];
    struct AC_automaton{
    	int cnt;
    	int ch[30010][2],fail[30010],last[30010];
    	queue <int> q;
    	inline void insert(){
    		int len = strlen(s), u(0), c;
    		for(int i = 0; i < len; ++i){
    			c = s[i] - '0';
    			if(!ch[u][c]) ch[u][c] = ++cnt;
    			u = ch[u][c];
    		}
    		last[u] = 1;
    	}
    	inline void getFail(){
    		for(int i = 0; i < 2; ++i){
    			if(ch[0][i]) q.push(ch[0][i]);
    		}
    		int u(0);
    		while(!q.empty()){
    			u = q.front(); q.pop();
    			for(int i = 0; i < 2; ++i){
    				if(ch[u][i]){
    					fail[ch[u][i]] = ch[fail[u]][i];
    					if(last[fail[ch[u][i]]]){
    						last[ch[u][i]] = 1;
    					}
    					q.push(ch[u][i]);
    				}
    				else{
    					ch[u][i] = ch[fail[u]][i];
    				}
    			}
    		}
    	}
    	void DFS(int u){
    		if(insta[u]){
    			printf("TAK");
    			exit(0);
    		}
    		if(last[u]) return;
    		if(vis[u]) return;
    		insta[u] = 1;
    		vis[u] = 1;
    		for(int i = 0; i < 2; ++i){
    			DFS(ch[u][i]);
    		}
    		insta[u] = 0;
    	}
    }qxz;
    int main(){
    	scanf("%d", &N);
    	for(int i = 1; i <= N; ++i){
    		scanf("%s", s);
    		qxz.insert();
    	}
    	qxz.getFail();
    	qxz.DFS(0);
    	printf("NIE");
    	return 0;
    }
    
  • 相关阅读:
    zookeeper历史版本下载
    RabbitMq集群搭建
    spring boot rabbitmq整合rabbitmq之消息持久化存储
    跨域
    Spring注入(IOC):
    AOP
    jsp自定义标签
    配置文件要注意的项
    线程
    URL转码
  • 原文地址:https://www.cnblogs.com/qixingzhi/p/9511378.html
Copyright © 2020-2023  润新知