[Ybt Advanced 2-5-5] [luogu P2444] Virus code/virus

Virus code / virus

Topic link: ybt high-efficiency advanced 2-5-5 / luogu P2444

General idea

There are some 01 strings, and then you are asked if there is a 01 string of unlimited length, so that any substring in this string is not one of the 01 strings given above.

Ideas

Then first see this question to determine whether some strings appear in a string, I think of AC automata.

Then we see that some strings cannot appear, then we use these strings to build a Trie tree, and then mark the positions of these strings.

Then think about it again, after you create a fail edge, the point it connects to must be its substring.
So if its substring contains a virus string, then it must also contain a virus string.
Then when you are building the fail side, deal with it.
(This is possible because the fail side of this point has already been established when you are processing it)

Then you think about how to do it. You can think that if you keep running the Trie tree, if you can find a ring where there is no point marked as containing a virus string, then you can make a string of unlimited length.

Why is there a ring? You would think that if there is no son when building a fail side, you can directly treat the son as the point of the fail side. If you do this, there may be a ring. If there is a ring, it is also feasible.

Code

#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>

using namespace std;

struct Trie {
    
    
	int son[2], fail;
	bool cnt;
}tree[30001];
int n, size;
char c[30001];
int tot;
queue <int> q;
bool in[30001], gone[30001];

void insert() {
    
    //AC 自动机插入
	int now = 0;
	
	for (int i = 0; i < size; i++) {
    
    
		int go = c[i] - '0';
		if (!tree[now].son[go]) tree[now].son[go] = ++tot;
		now = tree[now].son[go];
	}
	
	tree[now].cnt = 1;//标记不能出现这个串
}

void get_fail() {
    
    //AC 自动机建 fail 边
	for (int i = 0; i <= 1; i++)
		if (tree[0].son[i]) {
    
    
			q.push(tree[0].son[i]);
			tree[tree[0].son[i]].fail = 0;
		}
	
	while (!q.empty()) {
    
    
		int now = q.front();
		q.pop();
		
		for (int i = 0; i <= 1; i++)
			if (tree[now].son[i]) {
    
    
				q.push(tree[now].son[i]);
				tree[tree[now].son[i]].fail = tree[tree[now].fail].son[i];
			}
			else tree[now].son[i] = tree[tree[now].fail].son[i];
		
		tree[now].cnt |= tree[tree[now].fail].cnt;
	}
}

bool find(int now) {
    
    //找是否有环
	if (in[now]) {
    
    
		printf("TAK");
		return 1;
	}
	
	if (gone[now]) return 0;//小小的优化
	
	in[now] = 1;
	gone[now] = 1;
	
	for (int i = 0; i <= 1; i++)
		if (!tree[tree[now].son[i]].cnt) {
    
    
			if (find(tree[now].son[i])) return 1;
		}
	
	in[now] = 0;
	
	return 0;
}

int main() {
    
    
	cin >> n;
	for (int i = 1; i <= n; i++) {
    
    
		cin >> c;
		size = strlen(c);
		insert();
	}
	
	get_fail();
	
	if (!find(0)) printf("NIE");
	
	return 0;
}

Guess you like

Origin blog.csdn.net/weixin_43346722/article/details/114461746