bzoj2938 AC自动机 + 拓扑排序找环

https://www.lydsy.com/JudgeOnline/problem.php?id=2938

题意:给出N个01病毒序列,询问是否存在一个无限长的串不存在病毒序列

正常来说,想要寻找一个串是否出现这些01序列可以直接跑AC自动机,这题反向问有没有无限长的不出现,说明在AC自动机上询问的时候,要避免经过所有病毒串标记的end结点以及需要寻找一个可以无限跑的环。

所以我们将字典树的边和失配指针的边都看作是一条有向边,如果存在一个环上没有病毒结尾的标记,那么他就是合法的。

值得一提的是,fail指针的意义是指向最长公共前后缀的下一个结点,因此如果一个节点的fail指针指向了一个危险结点,则这个结点也是危险的,因为他指向的点一定是他的后缀。

 

#include <map>
#include <set>
#include <ctime>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
inline int read(){int now=0;register char c=getchar();for(;!isdigit(c);c=getchar());
for(;isdigit(c);now=now*10+c-'0',c=getchar());return now;}
#define For(i, x, y) for(int i=x;i<=y;i++)  
#define _For(i, x, y) for(int i=x;i>=y;i--)
#define Mem(f, x) memset(f,x,sizeof(f))  
#define Sca(x) scanf("%d", &x)
#define Sca2(x,y) scanf("%d%d",&x,&y)
#define Sca3(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define Scl(x) scanf("%lld",&x);  
#define Pri(x) printf("%d\n", x)
#define Prl(x) printf("%lld\n",x);  
#define CLR(u) for(int i=0;i<=N;i++)u[i].clear();
#define LL long long
#define ULL unsigned long long  
#define mp make_pair
#define PII pair<int,int>
#define PIL pair<int,long long>
#define PLL pair<long long,long long>
#define pb push_back
#define fi first
#define se second 
typedef vector<int> VI;
const double eps = 1e-9;
const int maxn = 5e4 + 10;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7; 
int N,M,K;
vector<int>Q[maxn];
int a[maxn];
struct AC{
    int next[2000010][2],fail[2000010];
    int end[2000010],ind[2000010];;
    int root,tot;
    int newnode(){
        next[tot][0] = next[tot][1] = -1;
        end[tot] = 0; ind[tot] = 0;
        return tot++;
    }
    void init(){
        tot = 0;
        root = newnode();
    }
    void insert(char *str){
        int p = root;
        for(int i = 0;str[i]; i ++){
            int id = str[i] - '0';
            if(next[p][id] == -1) next[p][id] = newnode();
            p = next[p][id];
        }
        end[p] = 1;
    }
    void Build(){
        queue<int>Q;
        for(int i = 0 ; i < 2; i ++){
            if(next[root][i] != -1){
                fail[next[root][i]] = root;
                Q.push(next[root][i]);
            }else{
                next[root][i] = root;
            }
        }
        while(!Q.empty()){
            int u = Q.front(); Q.pop();
            for(int i = 0 ; i < 2; i ++){
                if(next[u][i] == -1){
                    next[u][i] = next[fail[u]][i];
                }else{
                    fail[next[u][i]] = next[fail[u]][i];
                    if(end[fail[next[u][i]]]){
                        end[next[u][i]] = 1;
                    }
                    Q.push(next[u][i]);
                }
            }
        }
    }
    bool solve(){
        for(int i = 0 ; i < tot; i ++){
            if(end[i]) continue;
            ind[next[i][0]]++;
            ind[next[i][1]]++;
        }
        queue<int>Q;
        for(int i = 0 ; i < tot; i ++){
            if(!end[i] && !ind[i]) Q.push(i);
        }
        while(!Q.empty()){
            int u = Q.front(); Q.pop();
            for(int i = 0 ; i < 2; i ++){
                ind[next[u][i]]--;
                if(!end[next[u][i]] && !ind[next[u][i]]) 
                    Q.push(next[u][i]);
            }
        }
        for(int i = 0 ; i < tot; i ++){
            if(!end[i] && ind[i]) return true;
        }
        return false;    
    }
}ac;
char str[maxn];
int main(){
    Sca(N);
    ac.init();
    For(i,1,N){
        scanf("%s",str);
        ac.insert(str);
    }
    ac.Build();
    if(ac.solve()) puts("TAK");
    else puts("NIE");
    return 0;
}

 

posted @ 2019-01-17 15:23  Hugh_Locke  阅读(214)  评论(0编辑  收藏  举报