[NOI2017]遊戲
阿新 • • 發佈:2020-12-10
題目
點這裡看題目。
分析
注意到,非 x
的賽道只有兩種賽車可選,所以如果只有 a,b,c
,那麼限制可以轉化為 2-SAT 的邊。下面我們用 \(\neg h_i\) 表示在 \(i\) 號位上不選擇 \(h_i\) 這輛車。我們可以如下轉化:
- 如果 \((i,h_i,j,h_j)\) 中, \(h_i\) 本身不可選,該限制自然作廢。
- 如果 \((i,h_i,j,h_j)\) 中, \(h_j\) 本身不可選,那麼 \(h_i\) 也不可選,即 \(h_i\rightarrow \neg h_i\) 。
- 如果 \((i,h_i,j,h_j)\) 中, 兩種車各自都可以選,那麼顯然連線 \(h_i\rightarrow h_j\)
現在考慮處理 x
。雖然我們不難想到 \(O(3^d\times m)\) 進行列舉,但是實際上我們只需要考慮 x
上選取 \(A,B,C\) 的情況。而 a
已經包含了選 \(B,C\) , b
已經包含了選 \(A,C\) 。如果我們將 x
均替換為 a
或 b
,那麼我們已經考慮了所有的情況。因此只需要 \(O(2^d\times m)\) 便可以。
小結:
- 將
x
替換做a,b
,利用其含義進行 " 部分列舉 " ,而避免了直接列舉的高複雜度。
程式碼
#include <cstdio> #define Opp( x ) ( x <= N ? x + N : x - N ) const int MAXN = 1e5 + 5; template<typename _T> void read( _T &x ) { x = 0; char s = getchar(); int f = 1; while( s < '0' || '9' < s ) { f = 1; if( s == '-' ) f = -1; s = getchar(); } while( '0' <= s && s <= '9' ) { x = ( x << 3 ) + ( x << 1 ) + ( s - '0' ), s = getchar(); } x *= f; } template<typename _T> void write( _T x ) { if( x < 0 ) putchar( '-' ), x = -x; if( 9 < x ) write( x / 10 ); putchar( x % 10 + '0' ); } template<typename _T> _T MIN( const _T a, const _T b ) { return a < b ? a : b; } struct Edge { int to, nxt; }Graph[MAXN * 10]; struct Ristriction { int x, y; char hx, hy; void Read() { scanf( "%d %c %d %c", &x, &hx, &y, &hy ); hx += 'a' - 'A', hy += 'a' - 'A'; } }R[MAXN]; int stk[MAXN], top; int id[MAXN]; char S[MAXN], fir[3] = { 'b', 'a', 'a' }, avail[3][2] = { { 'b', 'c' }, { 'a', 'c' }, { 'a', 'b' } }; int seq[10], xtot; int head[MAXN], DFN[MAXN], LOW[MAXN], bel[MAXN]; int N, M, D, cnt, tot, ID; bool in[MAXN]; void AddEdge( const int from, const int to ) { Graph[++ cnt].to = to, Graph[cnt].nxt = head[from]; head[from] = cnt; } void Tarjan( const int u ) { DFN[u] = LOW[u] = ++ ID; in[stk[++ top] = u] = true; for( int i = head[u], v ; i ; i = Graph[i].nxt ) if( ! DFN[v = Graph[i].to] ) Tarjan( v ), LOW[u] = MIN( LOW[u], LOW[v] ); else if( in[v] ) LOW[u] = MIN( LOW[u], DFN[v] ); if( DFN[u] == LOW[u] ) { int v; tot ++; do in[v = stk[top --]] = false, bel[v] = tot; while( v ^ u ); } } void Clean() { ID = tot = top = cnt = 0; for( int i = 1 ; i <= N * 2 ; i ++ ) head[i] = LOW[i] = DFN[i] = bel[i] = 0; } bool Chk() { Clean(); for( int i = 1 ; i <= N ; i ++ ) id[i] = S[i] - 'a'; for( int i = 1 ; i <= M ; i ++ ) { if( R[i].hx == S[R[i].x] ) continue; if( R[i].hy == S[R[i].y] ) { int t = ( R[i].hx == fir[id[R[i].x]] ? R[i].x : Opp( R[i].x ) ); AddEdge( t, Opp( t ) ); } else { int u = ( R[i].hx == fir[id[R[i].x]] ? R[i].x : Opp( R[i].x ) ), v = ( R[i].hy == fir[id[R[i].y]] ? R[i].y : Opp( R[i].y ) ); AddEdge( u, v ), AddEdge( Opp( v ), Opp( u ) ); } } for( int i = 1 ; i <= N * 2 ; i ++ ) if( ! DFN[i] ) Tarjan( i ); for( int i = 1 ; i <= N ; i ++ ) if( bel[i] == bel[i + N] ) return false; return true; } int main() { bool flg = false; read( N ), read( D ); scanf( "%s", S + 1 ), read( M ); for( int i = 1 ; i <= M ; i ++ ) R[i].Read(); for( int i = 1 ; i <= N ; i ++ ) if( S[i] == 'x' ) seq[++ xtot] = i; for( int s = 0 ; s < ( 1 << xtot ) ; s ++ ) { for( int i = 1 ; i <= xtot ; i ++ ) S[seq[i]] = 'a' + ( s >> ( i - 1 ) & 1 ); if( flg = Chk() ) break; } if( ! flg ) { puts( "-1" ); return 0; } for( int i = 1 ; i <= N ; i ++ ) putchar( avail[id[i]][bel[i + N] < bel[i]] - 'a' + 'A' ); putchar( '\n' ); return 0; }