腾讯----贪吃的小Q
文章目录
一、题目描述
小Q的父母要出差N天,走之前给小Q留下了M块巧克力。小Q决定每天吃的巧克力数量不少于前一天吃的一半,但是他又不想在父母回来之前的某一天没有巧克力吃,请问他第一天最多能吃多少块巧克力
输入描述:
每个输入包含一个测试用例。
每个测试用例的第一行包含两个正整数,表示父母出差的天数N(N<=50000)
和巧克力的数量M(N<=M<=100000)。
输出描述:
输出一个数表示小Q第一天最多能吃多少块巧克力。
输入例子1:
3 7
输出例子1:
4
二、分析
-
首先我们可能会想到从最后一天吃的巧克力的数量来往前反推第一天吃巧克力的数量,但是我们并没有一个合适的值来进行反推,所以直接pass掉
-
那么我们就只能在第一天下手,我们就
枚举第一天所有可能吃掉的巧克力的数量,然后根据每个数量计算N天一共吃掉的巧克力的数量和M块巧克力的数量进行比较
。 -
如果从[1....M]逐个进行枚举,那么肯定是可以的,但是效率比较低
,那么什么方法适合这种枚举的场景呢----->二分查找
二分查找详解 -
举例:
n=3 m=7
我们有七块巧克力
1 2 3 4 5 6 7
首先我们找到中间位置的巧克力个数(向上取整,因为没有3.5个巧克力)(1+7+1)/2=4
就是4位置的巧克力
然后我们以它作为第一天的起始巧克力个数对这些天所需要的总巧克力个数进行求和,
最终的结果总巧克力数目如果等于m那么直接返回4,如果小于m,那么可能存在
更优的解在[5,7]区间内,那么需要在5位置到7位置中间位置继续做相同的操作。
如果大于m,那么证明我们第一天给的巧克力的数目太多了,需要在[1-3]区间内继续找合适的解。
三、代码
#include<iostream>
using namespace std;
//n代表天数,m代表巧克力的数量
int n, m;
//函数用来求第一天吃mid块巧克力,根据题意N天共吃掉巧克力的数量
int sum(int &mid)
{
int tmp = mid;
int total = tmp;
for (int i = 0; i < n -1; ++i)
{
tmp = (tmp + 1) / 2;
total += tmp;
}
return total;
}
int fun()
{
int l = 1;
int r = m;
while (l <= r)
{
int mid = (l + r + 1) / 2;
int bool_int = sum(mid);
if (bool_int == m)
{
return mid;
}
else if (bool_int < m)
{
l = mid + 1;
}
else
{
r = mid - 1;
}
}
return r;
}
int main()
{
cin >> n >> m;
cout << fun() << endl;
return 0;
}