题目
点这里看题目。
分析
注意到,非 x
的赛道只有两种赛车可选,所以如果只有 a,b,c
,那么限制可以转化为 2-SAT 的边。下面我们用 (
eg 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 ightarrow eg h_i) 。
- 如果 ((i,h_i,j,h_j)) 中, 两种车各自都可以选,那么显然连接 (h_i ightarrow h_j) 和 ( eg h_j ightarrow eg h_i) 。
现在考虑处理 x
。虽然我们不难想到 (O(3^d imes m)) 进行枚举,但是实际上我们只需要考虑 x
上选取 (A,B,C) 的情况。而 a
已经包含了选 (B,C) , b
已经包含了选 (A,C) 。如果我们将 x
均替换为 a
或 b
,那么我们已经考虑了所有的情况。因此只需要 (O(2^d imes 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( '
' );
return 0;
}