题解 P2444 【[POI2000]病毒】
活见鬼了总
好吧,考察了一下AC自动机的性质特别是对fail指针的理解。(苯蒟蒻显然不理解)
先看看样例。
(假设您现在已经依据样例画好了一棵trie树)
经过反复观察
发现可以考虑搜一下(因为成功找到后就退出,所以不会炸····)
搞一个vis数组,若在搜索过程中又遇到了标记处,即可说明循环了,就成功了
然后记得回溯
然后您可能会打出如下代码:
#include<bits/stdc++.h>
using namespace std;
const int N=300010;
int n,c[N][2],tot=0,cnt[N];
bool end[N];
int fail[N];
char ch[30010];
inline void insert(char *p){
int now=0,len=strlen(p);
for(int i=0;i<len;++i){
int s=p[i]-'0';
if(!c[now][s])c[now][s]=++tot;
now=c[now][s];
}
end[now]=1;
}
queue<int> q;
inline void build(){
int now=0;
for(int i=0;i<2;++i){
if(c[now][i]) fail[c[now][i]]=now,q.push(c[now][i]);
}
while(!q.empty()){
int x=q.front();q.pop();
for(int i=0;i<2;++i){
if(c[x][i]) fail[c[x][i]]=c[fail[x]][i],q.push(c[x][i]);
else c[x][i]=c[fail[x]][i];
}
}
}
bool vis[N];
bool check(int now){
vis[now]=1;
for(int i=0;i<2;++i){
if(vis[c[now][i]]) return 1;
if(!end[c[now][i]]){
if(check(c[now][i])) return 1;
}
}
vis[now]=0;
return 0;
}
int main()
{
// freopen("test.in","r",stdin);
// freopen("test.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;++i)scanf("%s",ch),insert(ch);
build();
if(check(0)) cout<<"TAK";else cout<<"NIE"<<endl;
}
结果挂了73feng。。。 然而只要第26行加上
end[c[x][i]]|=end[c[fail[x]][i]]
即可。你懂的呀