题目大意:给出一些01串,问是否存在一个无限长的串不包含这些串中的任意一个。
总长不超过30000。
建立AC自动机,则问题转化为在AC自动机上找环。考虑什么样的节点不能走。若一个节点是单词节点,那么所有fail指向它的节点一定包含了它作为后缀,所以这些节点都不能走。所以对于一个节点,如果它的fail节点危险,那么它也危险。所以不走危险节点,DFS查找是否有环即可。
由tarjan的过程类比,如果某次从一个点出发找不到环,那么之后这个点也不会再找到环了,所以访问后要进行标记,不再走这个点。
要注意的是三目运算符优先级比逗号运算符高,所以一定要记得加括号。
#include<cstdio>
#include<cstring>
#include<queue>
#define gm 30001
using namespace std;
struct node
{
node *s[2],*fail;
bool da,vis;
node():s(),fail(),da(),vis(){}
inline void* operator new(size_t)
{
static char pool[gm*sizeof(node)];
static node* s=(node*)pool;
static size_t k=-1;
return s+ ++k;
}
bool dfs()
{
if(da) return 0;
if(vis) return 1;
vis=1;
return (s[0]->dfs()||s[1]->dfs())?1:(da=1,0);
}
};
struct trie
{
node *rt;
trie():rt(new node){}
inline void insert(const char *s)
{
node *now=rt;
while(*s)
{
node *&x=now->s[*s-'0'];
if(!x) x=new node;
now=x;
++s;
}
now->da=1;
}
};
struct aho:public trie
{
aho():trie(){}
inline void operator () ()
{
queue<node*> q;
rt->fail=rt;
if(!rt->s[0]) rt->s[0]=rt;
else rt->s[0]->fail=rt,q.push(rt->s[0]);
if(!rt->s[1]) rt->s[1]=rt;
else rt->s[1]->fail=rt,q.push(rt->s[1]);
while(!q.empty())
{
node *now=q.front();q.pop();
now->da|=now->fail->da;
if(!now->s[0]) now->s[0]=now->fail->s[0];
else now->s[0]->fail=now->fail->s[0],q.push(now->s[0]);
if(!now->s[1]) now->s[1]=now->fail->s[1];
else now->s[1]->fail=now->fail->s[1],q.push(now->s[1]);
}
}
inline const char* circle()
{
return rt->dfs()?"TAK":"NIE";
}
}tr;
int n;
char s[gm];
int main()
{
scanf("%d",&n);
while(n--)
{
scanf("%s",s);
tr.insert(s);
}
tr();
printf("%s\n",tr.circle());
return 0;
}

本文介绍了一种利用AC自动机解决特定字符串匹配问题的方法,即判断是否存在无限长的字符串不包含一组给定的子串。通过构建AC自动机并进行深度优先搜索,实现了对该问题的有效解决。
444

被折叠的 条评论
为什么被折叠?



