[蓝桥杯 2022 省 B] 刷题统计
题目描述
小明决定从下周一开始努力刷题准备蓝桥杯竞赛。他计划周一至周五每天做 a a a 道题目,周六和周日每天做 b b b 道题目。请你帮小明计算,按照计划他将在第几天实现做题数大于等于 n n n 题?
输入格式
输入一行包含三个整数 a , b a, b a,b 和 n n n.
输出格式
输出一个整数代表天数。
样例 #1
样例输入 #1
10 20 99
样例输出 #1
8
提示
对于 50 % 50 \% 50% 的评测用例, 1 ≤ a , b , n ≤ 1 0 6 1 \leq a, b, n \leq 10^{6} 1≤a,b,n≤106.
对于 100 % 100 \% 100% 的评测用例, 1 ≤ a , b , n ≤ 1 0 18 1 \leq a, b, n \leq 10^{18} 1≤a,b,n≤1018.
蓝桥杯 2022 省赛 B 组 C 题。
思路
首先定义一个辅助函数ceilDiv
,用于实现向上取整的除法操作。
在main
函数中,首先读取输入的
a
a
a,
b
b
b和
n
n
n,然后定义两个变量
l
l
l和
r
r
r,分别表示二分查找的左边界和右边界。这里
r
r
r的初始值设置得非常大,足以覆盖题目中给定的
n
n
n的最大值。
接下来进入一个while
循环。在每次循环中,计算出当前的中点mid
,然后判断是否满足条件,即在mid
天内,小明做题的总数大于等于
n
n
n。如果满足条件,那么将左边界更新为mid
,否则将右边界更新为mid
。这个过程一直持续到左右边界之间只差1为止。
退出while
循环后,先计算出小明在
l
l
l天内做题的总数,然后从
n
n
n中减去这个数量,得到剩余的题目数量tmp
。同时,将答案ans
初始化为
l
l
l乘以7,这是因为每周有7天。
然后判断tmp
是否小于等于5乘以
a
a
a,也就是判断剩余的题目数量是否可以在周一到周五之间完成。如果可以,那么直接将tmp
除以
b
b
b并向上取整,然后加到ans
上;否则,将tmp
减去5乘以
a
a
a,然后将5和tmp
除以
b
b
b并向上取整的结果都加到ans
上。
最后,输出ans
,这就是小明实现做题数大于等于
n
n
n的最少天数。
注意
为了防止溢出,在进行二分查找时,应该使用 (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;
}