51nod 1557 两个集合 (二分搜索,思维逻辑好题)

传送门51nod 1557



题目大意

题目意思有点绕,大家好好理解一下,我就不再复述了。只需要注意是互不相同的整数。



参考51nod 1557 题解。



思路

很容易知道,数字应该是成对出现的,即若两个数满足 x、a-x 的关系则都在集合 A,若两个数满足 x、b-x 的关系则都在集合 B。


我们只考虑不符合条件的情况,由于数互不相同,对于某个数 x ,如果既不存在 a-x 属于集合 A,又不存在 b-x 属于集合 B,则为 NO。


对于某个数 x,如果既存在 a-x 又存在 b-x,就一定不行吗? 不是的,也有可能存在一个数字 d 使得 x 和 a-x 是一对,d 和 b-x是一对,或者, x 和 b-x 是一对,d 和 a-x 是一对。是一对的意思就是它们属于同一个集合。


换种适合编程的描述就是:对于数x ,若 a-x 和 b-x 都存在。如果 x 属于集合 A,则 b-x 一定不属于集合 B,否则 x 就会冲突。所以 b-x 一定属于集合 A,则必存在 a-(b-x) 属于集合 A。反之,如果 x 属于集合 B,则 a-x 一定不属于集合 A,否则 x 就会冲突。所以 a-x 一定属于集合 B,则必存在 b-(a-x) 属于集合 B。


除了以上的三种情况,剩下的都是合法的了,输出 YES。


说的自己都晕了……慢慢理解吧……



具体实现

由于数据范围为 10^5,所以应该采用低于 O(n^2) 的算法,这里用的是二分。先排序,后用 lower_bound 函数对每个 x 判断是否存在 a-x 和 b-x 以及 a-(b-x) 和 b-(a-x)。



代码

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;

int main()
{
	int i,n,a,b,f,pa,pb,pc,pd,p[100010];
	scanf("%d%d%d",&n,&a,&b);
	for(i=0;i<n;i++) scanf("%d",&p[i]);
	sort(p,p+n);
	f=1;
	for(i=0;i<n;i++)
	{
		pa=lower_bound(p,p+n,a-p[i])-p;	    //a-x 的位置 
		pb=lower_bound(p,p+n,b-p[i])-p;     //b-x 的位置 
		pc=lower_bound(p,p+n,a-(b-p[i]))-p;	//a-(b-x) 的位置 
		pd=lower_bound(p,p+n,b-(a-p[i]))-p; //b-(a-x) 的位置 
		if((p[pa]!=a-p[i]&&p[pb]!=b-p[i])) 
		{ //如果 a-x 和 b-x 都不存在 
			f=0;
			break;
		}			
		if((p[pa]==a-p[i]&&p[pc]!=a-(b-p[i]))&&(p[pb]==b-p[i]&&p[pd]!=b-(a-p[i])))
		{ //在 a-x和 b-x都存在的情况下,如果 a-(b-x)和 b-(a-x)都不存在 
			f=0;
			break;
		}
	}
	if(f) printf("YES\n");
	else printf("NO\n");
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值