题目描述

给你a,b和n个数p[i],问你如何分配这n个数给A,B集合,并且满足:

若x在集合A中,则a-x必须也在集合A中。

若x在集合B中,则b-x必须也在集合B中。

思路

因为p[i]是正数,所以一定要小于max(a,b)

用map<ll,ll> mp记录p[i]的下标 i

如果a-p[i]这个数存在,就和i配对,否则令i和n+1配对;

如果b-p[i]这个数存在,就和i配对,否则令i和0配对。

若存在某个数x,既不能放A集合,也不能放B集合,那么两个集合的并查集一定会相交。

因为A B两集合分别和0 n+1连接,所以在对father[ ]初始化的时候,把边界扩展到0-n+1

void init()
{
	for(ll i=0;i<=n+1;i++)
		f[i]=i;
}

AC代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+5;

ll a,b,n;
ll p[maxn],f[maxn];
map<ll,ll> mp;

void init()
{
	for(ll i=0;i<=n+1;i++)
		f[i]=i;
}
ll find(ll x)
{
	if(x!=f[x]) f[x]=find(f[x]);
	return f[x];
}
void union1(ll a,ll b)
{
	ll fa=find(a);
	ll fb=find(b);
	if(fa!=fb) f[fa]=fb;
}
void solve()
{
	for(ll i=1;i<=n;i++)
	{
		if(mp[b-p[i]]) union1(i,mp[b-p[i]]);
		else union1(i,0);//b集合不能放 就和0连接
		if(mp[a-p[i]]) union1(i,mp[a-p[i]]);
		else union1(i,n+1);
	}
	ll f0=find(0),fn=find(n+1);
	if(f0==fn)//a b都不能放 一定会相交
		printf("NO\n");
	else 
	{	
		printf("YES\n");
		for(ll i=1;i<=n;i++)
		{
			if(find(i)==f0)
				printf("0 ");
			else printf("1 ");
		}
		printf("\n");
	}		
}

int main()
{
	cin>>n>>a>>b;
	ll maxx=0;
	for(ll i=1;i<=n;i++)
	{
		cin>>p[i];
		mp[p[i]]=i;
		maxx=max(maxx,p[i]);
	}
	if(maxx>=max(a,b)) printf("NO\n");
	else {init();solve();}
	return 0;
}