蓝桥杯大学模拟赛(二) - 程序设计:植物大战僵尸题解


题目描述

植物⼤战僵⼫为近来很⽕的⼀款游戏。⽽这⼀次我们不⼀样,我们要提前养成植物然后来抵抗僵 ⼫。

你的 n 个植物已经从左到右排成了⼀排,编号从 1n ,起始的时候,他们的防御都是 0 ,⽽你的 任务就是来提⾼他们的防御。

你⼀共有 m 天的时间进⾏备战,起始你在整个植物的最左边,每天你 必须向左或向右移动⼀格, 到达第 ai 棵植物的时候,你给这个植物增加 m 点的防御。

众所周知,根据⽊桶原理,整排植物的防御取决于最低防御的⼀棵植物,你想让 天以后的整排植 物的防御⼒最⾼,请问最⾼能是多少呢?

输入描述

输入数据第一行包含以空格隔开的两个整数 n,m分别表示植物总数和你的备战天数

第二行包含以空格隔开的 n 个整数 a1.a2,…,an,表示每次一个植物可以增加的防御力

输出描述

输出⽂件共⼀⾏包括⼀个整数,表示整排植物可以达到的最⼤防御⼒

数据范围

1

输入

4 8
3 2 6 6

输出

6

算法分析

二分答案的防御力 + 贪心的去验证答案的正确性

答案很明显是要求,防御力最大时的最小值。最大的最小问题可以想到使用二分法求解。

二分答案,但是怎么验证这个答案是正确的呢?

我们贪心的去看,每次都保证一个植物是在当前答案**(mid变量)**标准以上。

因此我们让当前这个植物(a[i])和右边的植物(a[i+1])搭配来回走动(核心)

所以当前植物会走**⌈(a[i] / mid)⌉** 次,右边植物会走**⌈(a[i] / mid)⌉ - 1**次

  • 最后使得所有植物都到达mid标准以上时,计算总和天数,与m备战天数相比较验证答案

算法过程

在这里插入图片描述

代码

#include <iostream>
#include <cstdio>
using namespace std;

const int maxn = 1e5 + 7;
long long n, m, mm, ans;
long long a[maxn], d[maxn];

//始终保证左边的数不低于p这个标准
//用右边的数来回走动去保证左边这个数

//二分答案的标准
//去验证在这个标准下每个植物要踩多少次
//与题目的天数去比较
bool check(long long p)
{
    long long sum = 0;  //总步数,即该标准下的天数
    long long temp = 0; //当前a[i]踩的步数
    long long tempn = 0; //用来记录搭配使得a[i]到达标准时,右边植物a[i+1]在搭配踩了多少步
    
    for (int i = 0; i < n; i++){
        if (p % a[i])
            temp = p / a[i] + 1;
        else
            temp = p / a[i];
        
        temp -= tempn;
        
        if (temp <= 0) {    //说明搭配的位置在单独处理它之前,已经被踩到这个标准了
            if (i != n - 1) {
                //因为每次要保证当前a[i]达到这个标准,所以最后一次会落在a[i]上
                //但是此时a[i+1]已经达到标准了
                //去处理a[i+2]的过程中会经过a[i+1]一次
                //而当i == n - 1  时a[n-1] 后无元素要处理,所以不用经过a[n - 1]
                temp = 1;
            }
            else{
                temp = 0;
            }
            tempn = 0;  //右边并未搭配
        }
        else
            tempn = temp - 1;   //右边搭配的使用,只比当前这个少踩一次
        
        sum += temp + tempn;
        
        if (sum > m)
            return false;
    }
    return true;
}

int main()
{
    scanf("%lld%lld", &n, &m);
    for (int i = 0; i < n; i++)
        scanf("%lld", &a[i]);
  
    long long l = 1, r = 1e18;  
    while (l <= r) {
        long long mid = (l + r) >> 1;
        
        if (check(mid)) {
            l = mid + 1;
            
        }
        else
            r = mid - 1;
    }
    
    printf("%lld\n", l - 1);
    
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

省下洗发水钱买书

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值