一.题目链接:
ZOJ-4062
二.题目大意:
n 个植物排成一排.
水壶只能移动 m 步.
水壶一步移动一个单位长度,所到达的位置,该植物的防御值会相应增加.
求浇水之后,所有植物防御值中最小值最大可以为多少.
三.分析:
二分答案即可.
不过要加限制条件,在 check(mid) 函数中 cnt 可能会暴 long long.
这是因为,假设 n == 1e5,mid == 1e17 ,a[i] 均为 1.
此时,cnt 为 1e22.
所以要在 cnt 超过 mid后,立即 return 0.
中间用滚动数组 f 和 s 分别代表当前和下一株植物的防御值.
还有就是要特判一下最后一株植物.
四.代码实现:
#include <set>
#include <map>
#include <ctime>
#include <queue>
#include <cmath>
#include <stack>
#include <vector>
#include <cstdio>
#include <sstream>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define eps 1e-6
#define pi acos(-1.0)
#define ll long long int
using namespace std;
const int M = (int)1e5;
const ll mod = (ll)1e9 + 7;
const int inf = 0x3f3f3f3f;
int n;
ll m;
int a[M + 5];
bool check(ll mid)
{
ll f, s, x;
f = s = 0;
ll cnt = 0;
int pos = 0;
for(int i = 1; i < n; ++i)
{
if(cnt > m)
return 0;
if(pos == i - 1)
{
s += a[i];
cnt++;
pos = i;
f = s;
s = 0;
}
if(pos == i)
{
x = mid - f;
if(x <= 0)
continue;
x = x / a[i] + !(x % a[i] == 0);
cnt += 2 * x;
s = a[i + 1] * x;
}
}
if(s < mid)
{
x = mid - s;
x = x / a[n] + !(x % a[n] == 0);
cnt += 2 * x - !(pos == n);
}
return cnt <= m;
}
/**
1
3 8
59 6 97
24
**/
int main()
{
int T;
scanf("%d", &T);
while(T--)
{
scanf("%d", &n);
scanf("%lld", &m);
for(int i = 1; i <= n; ++i)
scanf("%d", &a[i]);
ll l = 0;
ll r = 1e18;
ll mid;
while(l < r)
{
mid = (l + r + 1) >> 1;
if(check(mid))
l = mid;
else
r = mid - 1;
}
printf("%lld\n", r);
}
return 0;
}