[POI2000]病毒 [洛谷]P2444

  • 题目描述
    二进制病毒审查委员会最近发现了如下的规律:某些确定的二进制串是病毒的代码。如果某段代码中不存在任何一段病毒代码,那么我们就称这段代码是安全的。现在委员会已经找出了所有的病毒代码段,试问,是否存在一个无限长的安全的二进制代码。
  • 输入输出格式

    • 输入格式:
      在文本文件WIR.IN的第一行包括一个整数n(n\le 2000)(n≤2000),表示病毒代码段的数目。以下的n行每一行都包括一个非空的01字符串——就是一个病毒代码段。所有病毒代码段的总长度不超过30000。
    • 输出格式:
      在文本文件WIR.OUT的第一行输出一个单词:
      TAK——假如存在这样的代码;
      NIE——如果不存在。
  • 思路
    这种多串匹配的问题,直接就想到AC自动机。
    不过这道题要变一下,转化为AC自动机上沿着trie上的边和fail指针走是否存在环。
    然后就判环。

#include <bits/stdc++.h>
using namespace std ;
const int maxn = 3e5+5 ;
int n, m, h, s[maxn][2], tim[maxn], fail[maxn], fa[maxn], tot, p, q, ch[maxn] ;
char pat[maxn] ;
void insert() {
    int len = strlen(pat+1) ;
    int i, j, k ;
    p = h ;
    for ( i = 1 ; i <= len ; i ++ ) {
        k = pat[i] - '0' ;
        if ( s[p][k] ) {
            p = s[p][k] ;   
        } else {
            ( s[p][k] = ++tot )[fa] = p ;
            p = s[p][k] ;
            ch[p] = pat[i] ;
        }
    }
    ++tim[p] ;
}
queue <int> Q ;
void calc() {
    int i, j, k, l, r, x ;
    Q.push(h) ;
    while ( !Q.empty() ) {
        x = Q.front() ;
        Q.pop() ;
        for ( i = 0 ; i < 2 ; i ++ )
            if ( s[x][i] ) {
                for ( p = x[fail] ; p && !s[p][i] ; p = p[fail] ) ;
                s[x][i][fail] = p? s[p][i]:h ;
                if ( s[x][i][fail][tim] ) s[x][i][tim] = 1 ;
                Q.push(s[x][i]) ;
            } else s[x][i] = s[x[fail]][i] ;
    }
}
bool vis[maxn], inq[maxn] ;
void check ( int x ) {
    printf ( "%d ch=%c fa=%d fail=%d tim=%d\n", x, ch[x], fa[x], fail[x], tim[x] ) ;
    for ( int i = 0 ; i < 2 ; i ++ ) {
        if ( s[x][i] ) check(s[x][i]) ;
    }
}
void dfs ( int x ) {
    if ( inq[x] ) return ;
    inq[x] = 1 ;
    vis[x] = 1 ;
    int i, u ;
    for ( i = 0 ; i < 2 ; i ++ ) {
        if ( s[x][i] ) {
            if ( s[x][i][vis] ) {
                puts("TAK") ;
                exit(0) ;
            } else if ( !s[x][i][tim] ) dfs(s[x][i]) ;
        }
    }
    vis[x] = 0 ;
}
int main() {
    int i, j, k ;
    scanf ( "%d", &n ) ;
    h = ++tot ;
    for ( i = 1 ; i <= n ; i ++ ) {
        scanf ( "%s", pat+1 ) ;
        insert() ;
    }
    calc() ;
    vis[1] = 1 ;
    dfs(1) ;
    puts("NIE") ;
    return 0 ;
}
点赞