#AC自动机#洛谷 2444 [POI2000]病毒 题目 分析 代码

给定若干01串,问是否存在无限长的01串任意子串不是给定的若干串


分析

如果在AC自动机上跳到了访问过的前缀即代表存在一个循环可以无限跳,
在AC自动机上记录哪些状态是不能访问的,在AC自动机上沿trie树标记已经走过


代码

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <queue>
#define rr register
using namespace std;
const int N=30011;
int n; char s[N];
bool Is_Virus[N],v[N];
struct I_AC_THE_TASK{
	int tot,trie[N][2],fail[N];
	inline void Insert(char *s){
        rr int len=strlen(s),now=1;
        for (rr int i=0;i<len;++i){
            if (!trie[now][s[i]^48]) trie[now][s[i]^48]=++tot;
            now=trie[now][s[i]^48];
        }
        Is_Virus[now]=1;
	}
    inline void Build(){
        rr queue<int>q; q.push(1);
        while (!q.empty()){
            rr int x=q.front(); q.pop();
            for (rr int i=0;i<2;++i)
            if (!trie[x][i]) trie[x][i]=trie[fail[x]][i];
                else {
                	fail[trie[x][i]]=trie[fail[x]][i],q.push(trie[x][i]);
					Is_Virus[trie[x][i]]|=Is_Virus[trie[fail[x]][i]];
				}
		}
    }
}AC;
inline void dfs(int x){
	if (v[x]) printf("TAK"),exit(0);
	if (Is_Virus[x]) return; v[x]=1;
	if (AC.trie[x][0]) dfs(AC.trie[x][0]);
	if (AC.trie[x][1]) dfs(AC.trie[x][1]);
	v[x]=0;
}
signed main(){
	scanf("%d",&n); AC.tot=1;
	for (rr int i=0;i<2;++i) AC.trie[0][i]=1;
	for (rr int i=1;i<=n;++i) scanf("%s",s),AC.Insert(s); AC.Build();
	dfs(1);
	return !printf("NIE");
}