Codeforces 468B Two Sets(超直白解释)

题意:

给你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;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值