这里有个技巧,就是关于怎么找到无限长的字符串,其实就是在ac机上寻找环,这个环中不允许有任何模板字符串的fail指针指着环的人任何一节。
所以用pos存是否该字符串存在模板字符串的,如果pos[fail[x]]是1,那么pos[x]必是1,因为在fail树中,父树永远出现在子树中,而且是后缀。
#include<bits/stdc++.h>
using namespace std;
const int MX=1e5+9;
int n,tot=0,pos[MX],t[MX<<2][2],fail[MX];
char s[MX];
void inst(){
int now=0;
for( int i=0 ; s[i] ; i++ ){
int a=s[i]-'0';
if( !t[now][a] )
t[now][a]=++tot;
now=t[now][a];
}
pos[now]=1;
}
void build(){
queue<int> que;
for( int i=0 ; i<=1 ; i++ )
if( t[0][i] )
que.push(t[0][i]);
while( !que.empty() ){
int now=que.front();
que.pop();
for( int i=0 ; i<=1 ; i++ ){
if( t[now][i] ){
que.push(t[now][i]);
fail[t[now][i]]=t[fail[now]][i];
pos[t[now][i]]|=pos[fail[t[now][i]]]; // 放这2个地方都可以,不过放下面会一个点多次赋值,
}
else
t[now][i]=t[fail[now]][i];
// pos[t[now][i]]|=pos[fail[t[now][i]]];
}
}
return ;
}
int vis[MX],v[MX],falg=0;
void dfs(int u){
for( int i=0 ; i<=1 ; i++ ){
if( !pos[t[u][i]] ){
if( v[t[u][i]] ){
if( vis[t[u][i]] ){
falg=1;
return ;
}
}
else{
vis[t[u][i]]=1,v[u]=1; // v是为了防止走已经走过的点,否则tle,因为从多个节点走可能走到同于一个节点,这样就导致重复走了
dfs(t[u][i]);
vis[t[u][i]]=0;
}
}
}
}
int main()
{
freopen("input.txt","r",stdin);
scanf("%d",&n);
for( int i=1 ; i<=n ; i++ ){
scanf("%s",s);
inst();
}
build();
dfs(0);
if( falg )
printf("TAK\n");
else
printf("NIE\n");
return 0;
}
来源:https://blog.csdn.net/weixin_44781226/article/details/102774117