题目描述
BaoBao and DreamGrid are playing the game Plants vs. Zombies. In the game, DreamGrid grows plants to defend his garden against BaoBao's zombies.
输入输出描述
题目大意
T 组测试用例
n株植物 机器人步数m(浇水次数)
机器人沿直线移动(向东或向西):屋内-植物1-植物2…-植物n-花园外
每移动一次浇水一次
每株植物增长速度不同ai,植物每次被浇水增长ai
花园防御能力取决于成长度最低的植物
找出使花园防御能力最高的机器人行动路线
例:4 8
3 2 6 6
路线:E(东),E,W(西),E,E,W,E,E
浇水后植物成长度6,6,12,6
防御力为6
思路:
最大化最小值 用二分搜索
条件c(x):m步内使每株植物成长度至少为x
x区间初始化[0,1e17]
当能满足条件c(x)时提高下界l=mid+1 即可找到最大的最小值
条件c(x)的判断函数实现:
最小值最小为0 符合 返回true
每株实现最小值需要浇几次水 num=(m+a[i]-1)/a[i]
每个点实现所需步数的方法为向下一点移动再回来(两点见反复横跳)直到实现指标(最小值)
b[i]存储机器人在每个点的步数
每个点步数的组成为与前一个点横跳的步数+与下一点的横跳步数
最小值不为0时 即所有植物都浇过水 步数最小为1 b[i]++
b[i]先存入前一点横跳的步数,再存入基础步数+1,与最小步数比较,不足则改为最小步数,将差值(与下一点的横跳步数)存入下一点
最小值不为0时 最后一个点(花园外)步数可能为0 加判断 if(i==N-1&&b[i]>=num) 未移动到最后一点 b[i]可以不+1
————————————————
版权声明:本文为优快云博主「挂印封侯」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.youkuaiyun.com/qq_44564169/article/details/97026286
代码详注
#include<bits/stdc++.h>
#define ll long long
#define pii pair<int,int>
#define double long double
using namespace std;
#define debug 0
const int maxn=1e5+50;
int n;
ll m;
ll a[maxn];//储存每个点的单次增长值
ll b[maxn];//储存在每个点的次数
bool judge(ll ans){//判断最小值ans是否能实现
if(ans==0)//最小值为0必定成立
{
return true;
}
for(int i=0;i<n+1;i++)//初始化
{
b[i]=0;
}
for(int i=0;i<n;i++)
{
ll num=(ans+a[i]-1)/a[i];//点实现最小值需要交税次数
if(i==n-1&&b[i]>=num)//
{
break;
}
b[i]++;//走到该点的一次
if(b[i]<num)//需要额外回撤
{
b[i+1]=num-b[i];//b[i+1]已经走过的步数
b[i]=num;//b[i]步数
}
}
ll sum=0;
for(int i=0;i<n+1;i++)
{
sum+=b[i];
if(sum>m)//总步数大于m
{
return false;
}
}
return true;
}
void solve(){
cin>>n>>m;
for(int i=0;i<n;i++)
{
cin>>a[i];
}
ll l=0,r=1e17;//初始化有效区间为0~1e17
while(l<=r)//二分寻找可实现的最大最小值
{
ll mid=(r-l)/2+l;
if(judge(mid))
{
l=mid+1;
}
else
{
r=mid-1;
}
}
cout<<l-1<<"\n";
return ;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int T;
cin>>T;
while(T--)
{
solve();
}
// solve();
return 0;
}