2018年ACM-ICPC青岛区域赛 E题 Plants vs. Zombies(代码详注版)

题目描述

        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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值