题目
https://www.matiji.net/exam/brushquestion/5/4347/179CE77A7B772D15A8C00DD8198AAC74?from=1
题目大意:一颗糖果有一张糖纸,p 张糖纸可以换取一颗糖果。换出来糖果的包装纸当然也能再换糖果。小度想吃 k 颗糖果,他需要买多少颗糖?
分析
显然答案具有单调性,即买的糖果越多,最后能吃到的糖果也越多,反之亦然。所以可以考虑二分。具体来说,二分需要买的糖果数,每次二分判断获取到的糖果数是否>=k。如果>=k,说明答案还可以减小。时间复杂度为 O ( T l o g 2 k i ) O(Tlog_2{k_i}) O(Tlog2ki)。
另外需要注意特殊情况:
- 当 p = 1 p=1 p=1的时候,只需要买1个就够了,因为可以一直用吃掉的糖果再换一个糖果,答案为1
- 当 k = 0 k=0 k=0的时候,显然不需要买糖果,答案为0
- 当 p = 1 且 k = 0 p=1且k=0 p=1且k=0的时候,显然也不需要买糖果,答案为0
所以可以先特判 k = 0 k=0 k=0,再特判 p = 1 p=1 p=1。
代码
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
bool check(ll x, ll p, ll k) {
ll y = x; // y表示糖纸数
ll sum = x; // 糖果数
while (y >= p) {
sum += y / p; // 当前糖纸数能换的糖果数
y = y % p + y / p; // 新的糖纸数 = 余下的糖纸数 + 新换的糖果的糖果纸数
}
return sum >= k;
}
int main( ) {
int T;
scanf("%d", &T);
while (T -- ) {
ll p, k;
scanf("%lld%lld", &p, &k);
// 特殊情况
if (k == 0) {
cout << 0 << endl;
continue;
}
if (p == 1) {
cout << 1 << endl;
continue;
}
ll l = 1, r = 1e9;
ll mid;
while (l < r) {
mid = l + r >> 1;
if (check(mid, p, k))
r = mid;
else
l = mid + 1;
}
cout << l << endl;
}
return 0;
}
总结
- 对于答案具有单调性的题目、或者最最问题(参考【2023百度之星备赛】码蹄集 BD202303 第五维度(二分 + 贪心)),都可以考虑采用二分解决
- 要注意题目中的特殊情况,必要的时候进行特判