luogu_P2444 [POI2000]病毒

传送门:https://www.luogu.org/problem/P2444

这种题一眼AC自动机(

但是AC自动机有些点要格外注意,比如:我这个傻缺就把ch[][]和fail[] 开成了char类型 QWQ

来看这道题在一个无限长的串中不让出现模式串。既然无限长那么我们就需要在trie图中找到一个合法的环不断循环下去

那么我们的任务就成了在trie图中找环(TIP—当一个点的fail指针指向的点为一个模式串的结尾,那么这个点也是不合法的)

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define R register
using namespace std;
int n,cnt,vis[40000],ch[40000][2],fail[40000];
char s[30010];
void make()
{
    int u=0,len=strlen(s);
    for(R int i=0;i<len;i++){
        int c=s[i]-'0';
        if(!ch[u][c]) ch[u][c]=++cnt;
        u=ch[u][c];
    }
    vis[u]=-1;
}
void AC(){
    queue<int> q;
    for(R int i=0;i<=1;i++){
        if(ch[0][i]){
            q.push(ch[0][i]);
            fail[ch[0][i]]=0;
        }
    }
    while(q.size()){
        int u=q.front();q.pop();
        for(R int i=0;i<=1;i++){
            if(!ch[u][i]) ch[u][i]=ch[fail[u]][i];
            else{
                int v=fail[u];
                while(v&&!ch[v][i]) v=fail[v];
                fail[ch[u][i]]=ch[v][i];
                q.push(ch[u][i]);
                if(vis[ch[fail[u]][i]]==-1) vis[ch[u][i]]=-1;
            } 
        }
    }
}
bool dfs(int u){
    vis[u]=1;
    for(R int i=0;i<=1;i++){
        if(vis[ch[u][i]]==1) return true;
        if(vis[ch[u][i]]==2||vis[ch[u][i]]==-1) continue;
        if(dfs(ch[u][i])) return true;
    }
    vis[u]=2;
    return false;
}
int main (){
    scanf("%d",&n);
    for(R int i=1;i<=n;i++){
        scanf("%s",s);
        make();
    }
    AC();
    if(dfs(0)) puts("TAK");
    else puts("NIE");
    return 0;
}
View Code

 

posted @ 2019-10-10 11:27  Ryn_Honey  阅读(115)  评论(0编辑  收藏  举报