Codeforces 468B Two Sets

题目链接

B. Two Sets
time limit per test
1 second
memory limit per test
256 megabytes
input
standard input
output
standard output

Little X has n distinct integers: p1, p2, ..., pn. He wants to divide all of them into two sets A and B. The following two conditions must be satisfied:

  • If number x belongs to set A, then number a - x must also belong to set A.
  • If number x belongs to set B, then number b - x must also belong to set B.

Help Little X divide the numbers into two sets or determine that it's impossible.

Input

The first line contains three space-separated integers n, a, b (1 ≤ n ≤ 105; 1 ≤ a, b ≤ 109). The next line contains n space-separated distinct integers p1, p2, ..., pn (1 ≤ pi ≤ 109).

Output

If there is a way to divide the numbers into two sets, then print "YES" in the first line. Then print n integers: b1, b2, ..., bn (bi equals either 0, or 1), describing the division. If bi equals to 0, then pi belongs to set A, otherwise it belongs to set B.

If it's impossible, print "NO" (without the quotes).

Sample test(s)
input
4 5 9
2 3 4 5
output
YES
0 0 1 1
input
3 3 4
1 2 4
output
NO
Note

It's OK if all the numbers are in the same set, and the other one is empty.


题意:N个不同的数字,要把它们分配到A集合和B集合。假设x在A集合,那么a-x也必须在A集合。假设x在B集合,那么b-x必须在B集合。问是否存在合法分配的方案,若有输出一个方案。


题解:简要分析:

1,假设一个数字x,a-x 和 b-x 都不存在,那么问题无解。

2,假设一个数字x,a-x 存在且 b-x 不存在,或者b-x存在且a-x不存在,那么我们就可以知道x,以及对应的(a-x)或(b-x)在哪个集合。

3,假设一个数字x,a-x 存在且 b-x 存在,那么这个数字暂时不能确定在哪个集合。

如果我们确定了一个数字x所在的集合,那么可以推导出它对应的(a-x)或(b-x)所对应的集合。我们可以往下层层推导,确定更多数字所在的集合。

现在我们来分析一个数字 x 不能被确定的情况。x不能确定那么,一定存在a-x 和 b-x,且a-x和b-x也不能确定。这样一定存在一些数字,既可以在A又可以在B。把数字看成点,能相互推导的数字连一条边,对于不能确定的数字来说,最后一定是形成了一些环,对于一个环上的数字来说,他们所在的集合一定是相同的。而他们既可以在A又可以在B。所以对于每个环上的数字,我们任意把它们分配到一个集合即可。

我们可以用很多方式来实现,当确定x所在的集合后,推导出其它数字所在的集合。我是用的dfs,因为一个数一旦确定就不会改变,每个数字只用搜一次,复杂度O(N)。

代码如下:

#include<stdio.h>
#include<algorithm>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<vector>
#include<iostream>
#include<string.h>
#include<string>
#include<math.h>
#include<stdlib.h>
#define inff 0x3fffffff
#define eps 1e-8
#define nn 210000
#define mod 1000000007
typedef long long LL;
const LL inf64=LL(inff)*inff;
using namespace std;
int n,a,b;
int A[nn];
map<int,int>ma;
int ans[nn];
bool ok;
void dfs(int id,int tem)
{
    int ix;
    if(tem==0)
        ix=a-A[id];
    else
        ix=b-A[id];
    if(ma.count(ix)==0)
    {
        ok=false;
        return ;
    }
    if(ans[ma[ix]]==-1)
    {
        ans[ma[ix]]=tem;
        dfs(ma[ix],tem);
    }
    if(tem==0)
    {
        ix=b-A[id];
    }
    else
        ix=a-A[id];
    if(ma.count(ix))
    {
        if(ans[ma[ix]]==-1)
        {
            ans[ma[ix]]=tem;
            dfs(ma[ix],tem);
        }
        if(ans[ma[ix]]!=tem)
        {
            ok=false;
            return ;
        }
    }
}
int main()
{
    int i;
    while(scanf("%d%d%d",&n,&a,&b)!=EOF)
    {
        ma.clear();
        ok=true;
        for(i=0;i<n;i++)
        {
            ans[i]=-1;
            scanf("%d",&A[i]);
            if(A[i]>=a&&A[i]>=b)
                ok=false;
            ma[A[i]]=i;
        }
        if(!ok)
        {
            puts("NO");
            continue;
        }
        int ix,fc;
        for(i=0;i<n;i++)
        {
            if(ans[i]!=-1)
                continue;
            ix=a-A[i];
            fc=b-A[i];
            if(ma.count(ix)&&!ma.count(fc))
            {
                ans[i]=0;
                dfs(i,0);
            }
            else if(ma.count(fc)&&!ma.count(ix))
            {
                ans[i]=1;
                dfs(i,1);
            }
        }
        for(i=0;i<n;i++)
        {
            if(ans[i]==-1)
            {
                ans[i]=0;
                dfs(i,0);
            }
        }
        if(!ok)
        {
            puts("NO");
            continue;
        }
        else
        {
            puts("YES");
            for(i=0;i<n;i++)
            {
                printf("%d%c",ans[i],i==n-1?'\n':' ');
            }
        }
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值