貌似这道题挺妙的样子?(其实是我太弱了)
也算是一篇(2-sat)的小结吧?
(2-sat)
给定一些布尔类型,每个点只有(0/1)两种取值,然后给出多种限制条件,要求方案。
考虑把每个点拆成两个点,如:(a->a_1,a_0)
然后对于每种限制条件进行不同的连边。
以这道题为例,
我们先考虑(d = 0)的条件。
那么注意到每个点它只有两个取值,我们可以先预处理出来。
然后这就是一个(2-sat)问题。
考虑连边条件。
如果一个条件是(x)为(A),则(y)为(B)
但是(x)位置上的点就是(a),那么说明这种条件是无法成立的,我们忽略。
如果(x)位置上不是(a)(比如是(B)),但(y)为(b),那么就有:若(x)为(A),则(y)为(B),但(y)不能为(B),所以(x)亦不能为(A),我们就把(x_A)连向(x_C)说明(x_A)不能取。
其他条件的话需要考虑周全,大概是这样连:
(x_A->y_B)
(y_{other} -> x_{other})(如果(y)不为(B),那么(x)亦不为(A))
这样我们就能处理(d = 0)的情况了
如果(dquad!=quad0)呢
因为(d)那么小,所以暴枚啊!
我们可以枚举(x)这个位置不能取那个点,这样枚举的话,如果(x)不能取(A),我们就把(B,C)存在的答案包括了进去,如果枚举(x)不能取(B),那么就把(A,C)的答案包括了进去。
所以对于每个(x)我们只要枚举(2)次。
复杂度(O(2^d*N))
#include<bits/stdc++.h>
using namespace std;
#define re register
#define rep( i, s, t ) for( re int i = s; i <= t; ++ i )
#define Next( i, x ) for( re int i = head[x]; i; i = e[i].next )
int read() {
char cc = getchar(); int cn = 0, flus = 1;
while(cc < '0' || cc > '9') { if( cc == '-' ) flus = -flus; cc = getchar(); }
while(cc >= '0' && cc <= '9') cn = cn * 10 + cc - '0', cc = getchar();
return cn * flus;
}
const int N = 5e5 + 5;
int head[N], dfn[N], low[N], s[N], cnt, n, m, top, tim, col, color[N];
int stac[N], top2, d, suit[N], ch[N][2];
struct E {
int to, next;
}e[N * 2];
struct Node{
int x, hx, y, hy;
}q[N];
char S[N];
void add( int x, int y ) {
e[++cnt] = (E) { y, head[x] }, head[x] = cnt;
}
void trajan( int x ) {
dfn[x] = low[x] = ++tim, s[++ top] = x;
Next( i, x ) {
int v = e[i].to;
if( !dfn[v] ) trajan( v ), low[x] = min( low[x], low[v] );
else if( !color[v] ) low[x] = min( low[x], dfn[v] );
}
if( low[x] == dfn[x] ) {
++ col;
while( s[top + 1] != x ) color[s[top--]] = col;
}
}
void doit() {
memset( head, 0, sizeof(head) ), memset( dfn, 0, sizeof(dfn) );
memset( low, 0, sizeof(low) ), memset( color, 0, sizeof(color) );
cnt = tim = top = col = 0;
rep( i, 1, m ) {
int x = q[i].x, y = q[i].y, u = x + q[i].hx * n, v = y + q[i].hy * n;
if( q[i].hx == suit[x] ) continue;
if( q[i].hy == suit[y] ) {
add( ch[x][ch[x][1] == u], ch[x][ch[x][1] != u] );
}
else add( u, v ), add( ch[y][ch[y][1] != v], ch[x][ch[x][1] != u]);
}
rep( i, 1, n ) { if( !dfn[ch[i][0]] ) trajan( ch[i][0] ); if( !dfn[ch[i][1]] ) trajan( ch[i][1] ); }
rep( i, 1, n ) if( color[ch[i][0]] == color[ch[i][1]] ) return ;
rep(i, 1, n) {
if( color[ch[i][0]] > color[ch[i][1]] ) printf("%c", ( ( ch[i][1] - 1 ) / n ) + 'A' );
else printf("%c", ( ( ch[i][0] - 1 ) / n ) + 'A' );
}
exit(0);
}
void dfs( int x ) {
if( x > d ) {
doit();
return ;
}
int now = stac[x];
suit[now] = 0, ch[now][0] = now + n, ch[now][1] = now + 2 * n,
dfs( x + 1 );
suit[now] = 1, ch[now][0] = now, ch[now][1] = now + 2 * n;
dfs( x + 1 );
}
signed main()
{
n = read(), d = read();
scanf( "%s", S );
int len = strlen(S);
rep( i, 0, len - 1 ) {
int now = i + 1;
if( S[i] == 'x' ) stac[++top2] = now;
if( S[i] == 'a' ) suit[now] = 0, ch[now][0] = now + n, ch[now][1] = now + 2 * n;
if( S[i] == 'b' ) suit[now] = 1, ch[now][0] = now, ch[now][1] = now + 2 * n;
if( S[i] == 'c' ) suit[now] = 2, ch[now][0] = now, ch[now][1] = now + n;
}
m = read();
rep( i, 1, m )
q[i].x = read(), q[i].hx = getchar() - 'A', q[i].y = read(), q[i].hy = getchar() - 'A';
dfs( 1 );
printf("-1");
return 0;
}