codeforces 469D
题意:
n 个数,给出常数 a、b, 要把这 n 个数分成两个不相交的集合 A、B 。且要满足:
如果某数 x 在 A 里,那么 a-x 也要在 A 里;如果 x 在 B 里,那么 b-x 也要在 B 里。
tags:
把 n 个数看成变量,要么在 A,要么在 B,即二判定性,可用 2-SAT 解。对于数 x, 用点 x2 表示它在 A集合,用点 x2+1 表示它在 B 集合。
但重点是如何连边:
1】如果对 x ,有 a-x 存在,那么就加双向边 [ x2, (a-x)2 ] , [ x2+1, (a-x)2+1 ] 。
表示如果 x 在 A集合,那么 a-x 也要在 A集合; 如 x 在 B 集合,那么 a-x 也要在 B集合。
2】如果对 x, 没有 a-x 存在,那么就加单向边 [ x2, x2+1 ] 。
表示如果推出了 x 在 A 集合,我们要否定这种情况,把它转回到 B 集合来。
// 469 D
#include<bits/stdc++.h>
using namespace std;
#pragma comment(linker, "/STACK:102400000,102400000")
#define rep(i,a,b) for (int i=a; i<=b; ++i)
#define per(i,b,a) for (int i=b; i>=a; --i)
#define mes(a,b) memset(a,b,sizeof(a))
#define INF 0x3f3f3f3f
#define MP make_pair
#define PB push_back
#define fi first
#define se second
typedef long long ll;
const int N = 200005;
int top, Stack[N<<1];
vector< int > G[N<<1];
bool mark[N<<1];
void Addedge(int u, int uval, int v, int vval) {
u = u*2+uval, v = v*2+vval;
G[u].PB(v);
G[u^1].PB(v^1);
}
bool dfs(int u, int fa)
{
if(mark[u^1]) return false;
if(mark[u]) return true;
mark[u] = true; Stack[top++] = u;
for(int to : G[u]) if(!dfs(to, u)) return false;
return true;
}
int n, a, b;
ll p[N];
map< ll, int > mp;
int main()
{
scanf("%d%d%d", &n, &a, &b);
rep(i,1,n) scanf("%d", &p[i]), mp[p[i]]=i;
bool flag;
rep(i,1,n) {
flag = false;
if(mp.find(a-p[i])!=mp.end()) Addedge(i, 0, mp[a-p[i]], 0), flag=true;
else G[i*2].PB(i*2+1);
if(mp.find(b-p[i])!=mp.end()) Addedge(i, 1, mp[b-p[i]], 1), flag=true;
else G[i*2+1].PB(i*2);
if(!flag) return printf("NO
"), 0;
}
for(int i=2; i<=n*2; i+=2)
{
if(mark[i]==false && mark[i^1]==false)
{
top = 0;
if(!dfs(i, 0)) {
while(top>0) mark[Stack[--top]] = false;
if(!dfs(i^1, 0)) return printf("NO
"), 0;
}
}
}
puts("YES");
for(int i=2; i<=n*2; i+=2)
if(mark[i]) printf("0 ");
else printf("1 ");
puts("");
return 0;
}