「洛谷P2444」病毒
分析:
先想想:如果构造出一个无限长的安全代码 再到 \(AC\) 自动机去匹配 会出现什么情况\(?\)
那当一位位匹配时 永远不会跳到某个病毒代码的结尾位置 然后 \(AC\) 自动机就会一直原地\(tp\)(
记病毒代码的结尾位置为 危险标记 因为匹配到结尾已表明出现了病毒代码段
所以 问题就变成 在 \(trie\) 图上找一个环 并且环上没有危险标记
而且要注意 从根节点出发 不经过任何危险标记 也能到达这个环
如果节点\(x\)的\(fail\)有危险标记 那这个点\(x\)也是危险的 因为\(fail\)是\(x\)的后缀
CODE:
点击查看代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#define reg register
using namespace std;
typedef long long ll;
const int N=3e4+5;
struct Trie{
int fail,num[2];
bool in;
}trie[N];
int n,tot;
queue<int> q;
char ch[N];
bool vis[N],book[N];
void ins(char a[])
{
int len=strlen(a),now=0;
for(int i=0;i<len;i++)
{
int qwq=a[i]-'0';
if(!trie[now].num[qwq]) trie[now].num[qwq]=++tot;
now=trie[now].num[qwq];
}
trie[now].in=true;
}
void AC()
{
if(trie[0].num[0]>0) q.push(trie[0].num[0]);
if(trie[0].num[1]>0) q.push(trie[0].num[1]);
while(!q.empty())
{
int now=q.front();
q.pop();
for(int i=0;i<=1;i++)
{
if(trie[now].num[i]>0)
{
q.push(trie[now].num[i]);
int k=trie[now].fail;
while(k&&trie[k].num[i]==0) k=trie[k].fail;
if(trie[k].num[i]==0) trie[trie[now].num[i]].fail=0;
else{
trie[trie[now].num[i]].fail=trie[k].num[i];
if(trie[trie[k].num[i]].in) trie[trie[now].num[i]].in=1;
}
}else trie[now].num[i]=trie[trie[now].fail].num[i];
}
}
}
void dfs(int x)
{
vis[x]=1;
for(int i=0;i<=1;i++)
{
if(vis[trie[x].num[i]]){puts("TAK");exit(0);}
else if(!trie[trie[x].num[i]].in&&!book[trie[x].num[i]])
{
book[trie[x].num[i]]=1;
dfs(trie[x].num[i]);
}
}
vis[x]=0;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%s",ch);
ins(ch);
}
AC(); dfs(0);
puts("NIE");
return 0;
}


浙公网安备 33010602011771号