【洛谷 P8780】[蓝桥杯 2022 省 B] 刷题统计 题解(二分查找+数学)

108 阅读2分钟

[蓝桥杯 2022 省 B] 刷题统计

题目描述

小明决定从下周一开始努力刷题准备蓝桥杯竞赛。他计划周一至周五每天做 aa 道题目,周六和周日每天做 bb 道题目。请你帮小明计算,按照计划他将在第几天实现做题数大于等于 nn 题?

输入格式

输入一行包含三个整数 a,ba, bnn.

输出格式

输出一个整数代表天数。

样例 #1

样例输入 #1

10 20 99

样例输出 #1

8

提示

对于 50%50 \% 的评测用例,1a,b,n1061 \leq a, b, n \leq 10^{6}.

对于 100%100 \% 的评测用例,1a,b,n10181 \leq a, b, n \leq 10^{18}.

蓝桥杯 2022 省赛 B 组 C 题。


思路

首先定义一个辅助函数ceilDiv,用于实现向上取整的除法操作。

main函数中,首先读取输入的aabbnn,然后定义两个变量llrr,分别表示二分查找的左边界和右边界。这里rr的初始值设置得非常大,足以覆盖题目中给定的nn的最大值。

接下来进入一个while循环。在每次循环中,计算出当前的中点mid,然后判断是否满足条件,即在mid天内,小明做题的总数大于等于nn。如果满足条件,那么将左边界更新为mid,否则将右边界更新为mid。这个过程一直持续到左右边界之间只差1为止。

退出while循环后,先计算出小明在ll天内做题的总数,然后从nn中减去这个数量,得到剩余的题目数量tmp。同时,将答案ans初始化为ll乘以7,这是因为每周有7天。

然后判断tmp是否小于等于5乘以aa,也就是判断剩余的题目数量是否可以在周一到周五之间完成。如果可以,那么直接将tmp除以bb并向上取整,然后加到ans上;否则,将tmp减去5乘以aa,然后将5和tmp除以bb并向上取整的结果都加到ans上。

最后,输出ans,这就是小明实现做题数大于等于nn的最少天数。

注意

为了防止溢出,在进行二分查找时,应该使用 (5 * a + 2 * b) <= n / mid 进行判断。如果使用 mid * (5 * a + 2 * b) <= n ,无法通过部分测试点。


AC代码

#include <iostream>
using namespace std;
using ll = long long;

ll ceilDiv(ll x, ll y) { return (x + y - 1) / y; }

int main() {
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);

	ll a, b, n;
	cin >> a >> b >> n;

	ll l = 0;
	ll r = 1e18 + 7;
	while (l + 1 < r) {
		ll mid = (l + r) >> 1;
		// cout << mid << "\n";
		if ((5 * a + 2 * b) <= n / mid) {
			l = mid;
		} else {
			r = mid;
		}
	}
	// cout << l << "\n";
	ll tmp = n - l * (5 * a + 2 * b);
	ll ans = l * 7;
	// cout << tmp << "\n";
	if (tmp <= 5 * a) {
		ans += ceilDiv(tmp, b);
	} else {
		tmp -= 5 * a;
		ans += 5 + ceilDiv(tmp, b);
	}
	cout << ans << "\n";
	return 0;
}