这题显然一遍一遍的枚举爆炸数时间肯定会超,但是这题答案具有单调性,所以我们可以用二分答案。
方法确定了,我们就要确定一下函数怎么写。因为每次爆炸所有魔物至少都会减少 B 点体力,所以如果爆炸数为 m ,那么我们可以直接让所有怪物的体力减少 B × m 点体力,最后再循环搜索。如果有魔物的体力大于 0 ,就算一下魔物还需要减多少 A - B 点体力才能消失,再用一个变量把那个数加起来。最后再比较,如果那个变量 <= m,返回 true ,否则返回 false 。AC代码如下:
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
long long a[100005],n, a,r = 1e10,l = 1,b;
bool check(long long m)
{
long long sum = 0,h[100005];
for(int i = 1;i <= n;i ++)h[i] = a[i] - b * m;
for(int i = 1;i <= n;i ++)
{
if(h[i] > 0)sum += ceil(h[i] / (double)(a - b));
if(sum > m)return false;
}
return true;
}
int main()
{
cin >> n >> a >> b;
for (int i = 1; i <= n; i ++)cin >> a[i];
while (l < r)
{
long long mid = (l + r) / 2;
if (check(mid))r = mid ;
else l = mid + 1;
}
cout << l;
return 0;
}
有两点需要注意:1. r的值不能过小,不然大数扫描不到;2.有些变量需要用到 long long,因为 B 的值能到 10^9 ,在乘个 m 就要爆 int 了。