Codeforces Round #275 (Div. 2) B Friends and Presents

题意是,你想给两个朋友送礼物,礼物表示成正整数,第一个朋友不喜欢能被x整除的礼物,第二个朋友不喜欢能被y整除的礼物,这两个朋友分别要送cnt1和cnt2个礼物,假设礼物从1到v编号,让你求出最小的v使得能送满足条件的礼物给两个朋友,两个朋友的礼物不能一样。其中上述变量满足 1 ≤ cnt1, cnt2 < 109 cnt1 + cnt2 ≤ 109 2 ≤ x < y ≤ 3·104
v最少是cnt1+cnt2,最大应该不超过cnt1+cnt2的3倍,也就是当x为2,y为3是,v应该取到最大值。
有了下界和上界,就可以用二分来找到最小的v值了,那么就判断一个数mid能不能以题目的要求分发礼物。
设礼物为1到mid,那么这mid个礼物就可一分成几类,分别是:能分发给第一个朋友但不能分发给第二个朋友的,能分发给第二个朋友但不能分发给第一个朋友的,既可以分发给第一个朋友也可以分发给第二个朋友的,既不可以分发给第一个朋友也不可以分发给第二个朋友的。其中第四种的个数最好求,就是mid / (x * y),第一种就是可以被y整除但不能被x整除的数的个数,为mid / y - mid / (x * y),第二种是可以被x整除但不能被y整除的数的个数,为mid / x - mid / (x * y),第三种为总数减去剩下三个的和,记为c。
我们将第一种的个数分给第一个朋友,第二种的个数分给第二个朋友,设分过之后他们还分别差c1和c2个礼物,这就要使用第三种礼物了,可以很快得到,如果c1,c2和c1+c2这三个数都不大于第三种的个数,那么mid就是符合题意的。这样我们就可以很快的判断mid能否满足题意,二分就可以了。
我写的时候忘记了带括号,一直错,最后才发现了,坑惨了。
代码如下:
#include <cstdio>
#include <iostream>

using namespace std;

long long cnt1, cnt2, x, y;

int main(void)
{
	while (cin >> cnt1 >> cnt2 >> x >> y) {
		long long l = cnt1 + cnt2;
		long long r = 3 * l;
		long long ans = cnt1 + cnt2;
		while (l <= r) {
			long long mid = (l + r) / 2;
			long long tmp1 = mid / x;
			long long tmp2 = mid / y;
			long long tmp3 = mid - tmp1 - tmp2 + mid / x / y;
			//真心坑,这里写错了,应该带上括号的,忘记带了,带上就过了 
			long long tmp4 = cnt1 - (tmp2 - mid / x / y);
			long long tmp5 = cnt2 - (tmp1 - mid / x / y);
			if (tmp4 <= tmp3 && tmp5 <= tmp3 && tmp4 + tmp5 <= tmp3) {
				ans = mid;
				r = mid - 1;
			} else {
				l = mid + 1;
			}
		}
		
		cout << ans << endl;
	}
	
	return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值