JZOJ5010. 编码

来源:互联网 发布:oracle 自动优化 工具 编辑:程序博客网 时间:2024/05/29 20:00

题目大意

给定n个01串,有一些串中有一个位置未确定。现在要判断,能否找到一种方案,使得任意一个串都不是其他任一串的前缀。

Data Constraint
n,500000

题解

考虑用Trie建图,跑2-SAT
将所有可能的串加入一个Trie里,每个点向它根路径上经过的点的另一个连边,表示这两种不能同时选。
然后Tarjan判一下就好了。

时间复杂度:O(n)

SRC

#include<cstdio>#include<cstdlib>#include<cstring>#include<iostream>#include<algorithm>#include<vector>using namespace std ;#define N 5000000 + 10#define M 500000 + 10struct Trie {    int Son[2] , fa ;    int In , Out , use ;} T[2*M] ;vector < int > P[2*M] ;char S[N] ;bool ok = 1 ;bool vis[N] , flag[N] ;int Node[5*N] , Next[5*N] , Head[N] , tot ;int DFN[N] , LOW[N] , Sta[N] , Bel[N] , Time ;int from[N] , Pre[N] , Suf[N] ;int n , Cnt , Col , Amo , Num = 1 ;void link( int u , int v ) {    Node[++tot] = v ;    Next[tot] = Head[u] ;    Head[u] = tot ;}int Rev( int x ) {    if ( x > 2 * n ) return 0 ;    return x > n ? x - n : x + n ;}void Insert( int len , int ID ) {    int now = 1 ;    for (int i = 1 ; i <= len ; i ++ ) {        int c = S[i] - '0' ;        if ( !T[now].Son[c] ) {            T[now].Son[c] = ++ Num ;            T[Num].fa = now ;        }        now = T[now].Son[c] ;    }    if ( !T[now].use ) T[now].use = ++ Amo ;    P[T[now].use].push_back( ID ) ;    if ( !T[now].In ) T[now].In = ++ Cnt ;    if ( !T[now].Out ) T[now].Out = ++ Cnt ;    link( T[now].In , Rev(ID) ) ;    link( ID , T[now].Out ) ;    from[ID] = now ;}void Build( int st ) {    if ( vis[st] ) return ;    vis[st] = 1 ;    int siz = P[T[st].use].size() ;    Pre[0] = Suf[siz+1] = 0 ;    for (int i = 1 ; i <= siz ; i ++ ) {        int now = Rev(P[T[st].use][i-1]) ;        Pre[i] = ++ Cnt ;        if ( Pre[i-1] > 0 ) link( Pre[i] , Pre[i-1] ) ;        link( Pre[i] , now ) ;    }    for (int i = siz ; i >= 1 ; i -- ) {        int now = Rev(P[T[st].use][i-1]) ;        Suf[i] = ++ Cnt ;        if ( Suf[i+1] > 0 ) link( Suf[i] , Suf[i+1] ) ;        link( Suf[i] , now ) ;    }    for (int i = 1 ; i <= siz ; i ++ ) {        int now = P[T[st].use][i-1] ;        if ( Pre[i-1] > 0 ) link( now , Pre[i-1] ) ;        if ( Suf[i+1] ) link( now , Suf[i+1] ) ;    }    int last = st ;    for (int x = T[st].fa ; x != 1 ; x = T[x].fa ) {        if ( T[x].In == 0 ) continue ;        link( T[last].Out , T[x].In ) ;        link( T[x].Out , T[last].In ) ;    }}void Tarjan( int x ) {    Sta[++Sta[0]] = x ;    flag[x] = 1 ;    DFN[x] = LOW[x] = ++ Time ;    for (int p = Head[x] ; p ; p = Next[p] ) {        if ( !DFN[Node[p]] ) {            Tarjan( Node[p] ) ;            LOW[x] = min( LOW[x] , LOW[Node[p]] ) ;        } else if ( flag[Node[p]] ) LOW[x] = min( LOW[x] , DFN[Node[p]] ) ;        if ( !ok ) return ;    }    if ( DFN[x] == LOW[x] ) {        Col ++ ;        while ( Sta[0] ) {            int now = Sta[Sta[0]] ;            Bel[now] = Col ;            flag[now] = 0 ;            Sta[0] -- ;            if ( Bel[now] == Bel[Rev(now)] ) { ok = 0 ; return ; }            if ( now == x ) break ;        }    }}bool Check() {    for (int i = 1 ; i <= 2 * n ; i ++ ) {        if ( !DFN[i] ) Tarjan( i ) ;        if ( !ok ) return 0 ;    }    return 1 ;}int main() {    freopen( "code.in" , "r" , stdin ) ;    freopen( "code.out" , "w" , stdout ) ;    scanf( "%d" , &n ) ;    Cnt = 2 * n ;    for (int i = 1 ; i <= n ; i ++ ) {        scanf( "%s" , S + 1 ) ;        int len = strlen( S + 1 ) , wz = 0 ;        for (int j = 1 ; j <= len ; j ++ ) {            if ( S[j] == '?' ) wz = j ;        }        if ( !wz ) Insert( len , i ) , link( n + i , i ) ;        else {            from[i] = from[n+i] = 1 ;            S[wz] = '0' ;            Insert( len , i ) ;            S[wz] = '1' ;            Insert( len , n + i ) ;        }    }    for (int i = 1 ; i <= 2 * n ; i ++ ) {        if ( !from[i] ) continue ;        Build( from[i] ) ;    }    if ( Check() ) printf( "YES\n" ) ;    else printf( "NO\n" ) ;    return 0 ;}

以上.

1 0
原创粉丝点击