Plants vs. Zombies

ZOJ - 4062

BaoBao and DreamGrid are playing the game Plants vs. Zombies. In the game, DreamGrid grows plants to defend his garden against BaoBao’s zombies.
Plants vs. Zombies(?)
(Image from pixiv. ID: 21790160; Artist: socha) There are nnn plants in DreamGrid’s garden arranged in a line. From west to east, the plants are numbered from 1 to nnn and the iii-th plant lies iii meters to the east of DreamGrid’s house. The iii-th plant has a defense value of did_idi​ and a growth speed of aia_iai​. Initially, di=0d_i = 0di​=0 for all 1≤i≤n1 \le i \le n1≤i≤n.DreamGrid uses a robot to water the plants. The robot is in his house initially. In one step of watering, DreamGrid will choose a direction (east or west) and the robot moves exactly 1 meter along the direction. After moving, if the iii-th plant is at the robot’s position, the robot will water the plant and aia_iai​ will be added to did_idi​. Because the water in the robot is limited, at most mmm steps can be done.The defense value of the garden is defined as min⁡{di∣1≤i≤n}\min{d_i | 1 \le i \le n}min{di​∣1≤i≤n}. DreamGrid needs your help to maximize the garden’s defense value and win the game.Please note that:Each time the robot MUST move before watering a plant;It’s OK for the robot to move more than nnn meters to the east away from the house, or move back into the house, or even move to the west of the house.InputThere are multiple test cases. The first line of the input contains an integer TTT, indicating the number of test cases. For each test case:The first line contains two integers nnn and mmm (2≤n≤1052 \le n \le 10^52≤n≤105, 0≤m≤10120 \le m \le 10^{12}0≤m≤1012), indicating the number of plants and the maximum number of steps the robot can take.The second line contains nnn integers a1,a2,…,ana_1, a_2, \dots, a_na1​,a2​,…,an​ (1≤ai≤1051 \le a_i \le 10^51≤ai​≤105), where aia_iai​ indicates the growth speed of the iii-th plant.It’s guaranteed that the sum of nnn in all test cases will not exceed 10610^6106.OutputFor each test case output one line containing one integer, indicating the maximum defense value of the garden DreamGrid can get.
Sample Input
2
4 8
3 2 6 6
3 9
10 10 1
Sample Output6
4
HintIn the explanation below, ‘E’ indicates that the robot moves exactly 1 meter to the east from his current position, and ‘W’ indicates that the robot moves exactly 1 meter to the west from his current position.For the first test case, a candidate direction sequence is {E, E, W, E, E, W, E, E}, so that we have d={6,6,12,6}d = {6,6,12,6}d={6,6,12,6} after the watering.For the second test case, a candidate direction sequence is {E, E, E, E, W, E, W, E, W}, so that we have d={10,10,4}d = {10, 10, 4}d={10,10,4} after the watering.

思路:这道题是求最小值的最大情况,可以考虑二分答案。我们对defense value进行二分。当defense value确定下来后,在确定m步之后能否满足当前的defense value,能满足说明答案要小于等于当前的defense value,否则就大于等于,相应进行二分即可。判断见代码注释。

代码

#include <stdio.h>
#include <stdbool.h>
inline int min(int Left,int Right){
      return Left<Right?Left:Right;
}

int T;


long long n, m;
int Grow[200005];
long long Times[200005];

//判断m步能是高度全部大于high🐎
inline bool Judgt(const long long high) {

	//算出第i棵植物要浇几次水才能得到高度high
	for (long long i = 0; i < n; i++) {
		Times[i] = (high - 1) / Grow[i];
	}
	//加个虚点
	Times[n] = 0;
	//已经走的步数
	long long Step = n;

	for (int i = 0; i < n; i++) {
		//处理边界条件,即最后两个点
		//如果最后一个点次数大于倒数第二个,直接往下走。(有个次数为0的虚点)
		if (i == n - 2 && Times[i] > Times[i + 1]) {
			Step += (Times[i] << 1) - 1;
			if (Step > m) {
				return false;
			}
			break;
		}

		//在i和i+1反复横跳,所以乘2
		//先处理完局部的就不用重复走,是最优的
		Step += Times[i] << 1;
		//超出步数就说明条件无法满足
		if (Step > m) {
			return false;
		}
		//接下来判段i+1在反复横跳处理完i后还需浇水的次数
		else if (Times[i + 1] > Times[i]) {
			Times[i + 1] -= Times[i];
		}
		else {
			Times[i + 1] = 0;
		}
	}

	return true;

}

int main() {
	scanf("%d", &T);
	while (T--) {
		scanf("%lld%lld", &n, &m);
		long long Left = 0, Right;
		int Temp = 2000000000;
		for (int i = 0; i < n; ++i) {
			scanf("%d", &Grow[i]);
			Temp = min(Temp, Grow[i]);
		}
		if (m < n) {
			puts("0");
			continue;
		}
		Right = Temp * (m-n+1);
		long long Ans =0;
		while (Left <= Right) {
			long long mid = (Left + Right + 1) >> 1;
			if (Judgt(mid)) {
				Ans = mid;
				Left = mid + 1;
			}
			else {
				Right = mid - 1;
			}
		}
		printf("%lld\n", Ans);
	}
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值