Codeforces Round 611 (Div. 3) - B. Candies Division (模拟,数学)

文章讨论了如何在圣诞老人分配n颗糖果给k个孩子时,保证公平性,即最少孩子的糖果数与最多孩子的糖果数差不超过1。解题策略是先平均分配,然后根据剩余糖果数和孩子数量的一半取最小值。
摘要由CSDN通过智能技术生成

圣诞老人有 n n n 粒糖果,他想把它们送给 k k k 个孩子。他想把尽可能多的糖果分给所有的 k k k 孩子。圣诞老人不能把一颗糖果分成几份,但他可以不用一些糖果。

假设得到最少糖果的孩子有 a a a 颗糖果,得到最多糖果的孩子有 b b b 颗糖果。那么,如果两个条件同时满足,圣诞老人就会满意:

  • b − a ≤ 1 b - a \le 1 ba1 (即 b = a b = a b=a b = a + 1 b = a + 1 b=a+1 );
  • 拥有 a + 1 a+1 a+1 颗糖果(注意 a + 1 a+1 a+1 不一定等于 b b b **)的孩子数量不超过 ⌊ k 2 ⌋ \lfloor\frac{k}{2}\rfloor 2k (小于或等于 ⌊ k 2 ⌋ \lfloor\frac{k}{2}\rfloor 2k )。

⌊ k 2 ⌋ \lfloor\frac{k}{2}\rfloor 2k k k k 除以 2 2 2 ,四舍五入到最接近的整数。例如,如果 k = 5 k=5 k=5 则为 ⌊ k 2 ⌋ = ⌊ 5 2 ⌋ = 2 \lfloor\frac{k}{2}\rfloor=\lfloor\frac{5}{2}\rfloor=2 2k=25=2

你的任务是找出圣诞老人能给孩子们的糖果的最大数量,这样他就会满意

您必须回答 t t t 个独立的测试案例。

输入

输入的第一行包含一个整数 t t t ( 1 ≤ t ≤ 5 ⋅ 1 0 4 1 \le t \le 5 \cdot 10^4 1t5104 ) - 测试用例的数量。

接下来的 t t t 行描述测试用例。 i i i -个测试用例包含两个整数 n n n k k k 1 ≤ n , k ≤ 1 0 9 1 \le n, k \le 10^9 1n,k109 )–糖果数量和孩子数量。

输出

为每个测试用例打印答案–圣诞老人能给孩子们的糖果的最大数量,这样他就会满意

Example
input

5
5 2
19 4
12 7
6 2
100000 50010

output

5
18
10
6
75015

记录此题,此题的思想方式值得学习。

首先明确,我们能给出去的不同的物品数量最多不能相差1,也就是说你最多也就只能给出两种数量。

这时候明确一点:我们可以给出 a a a 的数量也可以给出 a + 1 a+1 a+1 的数量的时候,那我们为什么不先给出 a a a 个数量的物品之后再去考虑剩下能再给出多少 1 1 1 呢?

以上就是这道题最值得学习的思想。
故我们就可以先把能够平均分出去的糖果全部分出去,然后再去考虑能多送出去多少个 1 1 1 个的糖果。
这里多分出去的糖果数量不能超过 ⌊ k 2 ⌋ \lfloor\frac{k}{2}\rfloor 2k,所以我们在 n n n % k k k k / 2 k/2 k/2 之间取最小值即可。

并且这里注意 n / k n/k n/k n − n n - n nn% k k k不一样的, n / k n/k n/k 表示的是能够平均分给每个人的糖果数量,而 n − n n-n nn% k k k 是平均分后所有人被分到的糖果数量的和。

#include<iostream>
using namespace std;

int main() {
	int q; cin >> q;
	while (q--) {
		int n, k; cin >> n >> k;

		//n%k是无法分出去给每个人的
		int res = n - n%k;
		//如上述,直接从二者中取最小值,这样得来的res就是最大的
		res += min(k/2,n%k);

		cout << res << endl;
	}
	return 0;
}

同时这道题也可以这样写,更有助于理解。

#include<iostream>
using namespace std;

int main() {
	int q; cin >> q;
	while (q--) {
		int n, k; cin >> n >> k;

		//先求出来能平均分的个数再乘以人数
		int res = k*(n/k);
		
		res += min(k/2,n%k);

		cout << res << endl;
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值