[AC自动机]luogu P2444 病毒

https://www.luogu.org/problem/P2444

 

分析

手玩样例可以发现一个无限长的安全串放到危险代码的AC自动机中匹配,一定会成环

将fail也视为一条单向边,DFS跑个不经过任何代码结尾的环即可

特殊的,如果一个点的fail指向一个代码的结尾,那么这个节点也是危险的(这个串的最长公共后缀是个危险代码)

 

#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <queue>
using namespace std;
const int N=3e4+10;
int fail[N],c[N][2],f[N],cnt=0;
bool vis[N],end[N],ok;
string s;
int n;

void Insert(string s) {
    int len=s.length(),x=0;
    for (int i=0;i<len;i++) {
        if (!c[x][s[i]-48]) f[c[x][s[i]-48]=++cnt]=x;
        x=c[x][s[i]-48];
    }
    end[x]=1;
}

void Build() {
    queue<int> q;
    while (!q.empty()) q.pop();
    if (c[0][0]) q.push(c[0][0]);
    if (c[0][1]) q.push(c[0][1]);
    while (!q.empty()) {
        int u=q.front();q.pop();
        end[u]|=end[fail[u]];
        for (int i=0;i<2;i++)
            if (c[u][i]) {
                q.push(c[u][i]);
                fail[c[u][i]]=c[fail[u]][i];
            }
            else c[u][i]=c[fail[u]][i];
    }
}

void DFS(int u) {
    if (end[u]) return;
    if (vis[u]) {
        printf("TAK\n");ok=1;
        return;
    }
    vis[u]=1;
    if (c[u][0]) DFS(c[u][0]);
    if (ok) return;
    if (c[u][1]) DFS(c[u][1]);
    if (ok) return;
    vis[u]=0;
}

int main() {
    scanf("%d",&n);
    for (int i=1;i<=n;i++) {
        cin>>s;
        Insert(s);
    }
    Build();
    DFS(0);
    if (!ok) printf("NIE\n");
}
View Code

 

posted @ 2019-08-07 07:44  Vagari  阅读(150)  评论(0编辑  收藏  举报