题意:
给你a,b和n个数p[i],问你如何分配这n个数给A,B集合,并且满足:
若x在集合A中,则a-x必须也在集合A中。
若x在集合B中,则b-x必须也在集合B中。
思路:
对于一个x来说,能分成以下4种情况(这里a!=b):
1.a-x不存在,b-x不存在。这种情况直接输出NO。
2.a-x存在,b-x不存在。这种情况把x和a-x放在集合A中。
3.a-x不存在,b-x存在。这种情况把x和b-x放在集合B中。
4.a-x存在,b-x存在。这种情况比较我们就不能直接确定要放A还是要放B了。
那么我们接下还需要判断是否存在y有a-y=b-x或者b-y=a-x其中之一存在。为什么是其中之一呢?假设有a-y=b-x和b-y=a-x同时存在,那么将两式子相减有x-y=y-x -> x*2=y*2 -> x=y成立,则有a-y=a-x=b-x -> a=b矛盾。所以上面两种情况只可能存在一种或都不存在。如果存在a-y=b-x,那么就把x和a-x和y和a-y(b-x)都放到集合A中。同理b-y=a-x存在的情况。如果都不存在,那么我们就无法决则把x和a-x和b-x放到集合A中还是集合B中,因为放到那一边都会剩下另一个无法去放,所以就输出NO。这里用并查集来维护即可。
#include<cstdio>
#include<map>
#include<algorithm>
using namespace std;
const int MAX=1e5+5;
int n,a,b,p[MAX],fa[MAX];
map<int,int> mp;
int Find(int x){
int r=x,t;
while(r!=fa[r]){
r=fa[r];
}
while(x!=r){
t=fa[x];
fa[x]=r;
x=t;
}
return r;
}
void Union(int u,int v){
int uu=Find(u);
int vv=Find(v);
if(uu!=vv){
fa[uu]=v;;
}
}
int main(){
scanf("%d%d%d",&n,&a,&b);
int Max=0;
for(int i=1;i<=n;i++){
scanf("%d",&p[i]);
mp[p[i]]=i;
Max=max(Max,p[i]);
}
if(Max>=max(a,b)) printf("NO\n");
else{
for(int i=0;i<=n+1;i++){
fa[i]=i;
}
for(int i=1;i<=n;i++){
if(mp[a-p[i]]) Union(i,mp[a-p[i]]);
else Union(i,n+1);
if(mp[b-p[i]]) Union(i,mp[b-p[i]]);
else Union(i,0);
}
int A=Find(0);
int B=Find(n+1);
if(A!=B){
printf("YES\n");
for(int i=1;i<=n;i++){
if(i!=1) printf(" ");
if(Find(i)==A) printf("0");
else printf("1");
}
printf("\n");
}
else printf("NO\n");
}
return 0;
}