CodeForces - 1118D2:喝咖啡(二分)

本文解析了一道算法竞赛题目,通过二分搜索和排序策略,解决了一个关于如何在最少时间内完成指定页数作业的问题。泰泰学长利用不同咖啡因含量的咖啡来提高工作效率,每天咖啡饮用顺序灵活,但遵循特定的咖啡因消耗规则。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原题链接
泰泰学长必须写他的课程作业。他的课程作业包含m 页.

为了提高效率,泰泰学长从某多多上买了n 杯咖啡. 对于第 i 杯咖啡泰泰学长可以摄取 ai 咖啡因. 泰泰学长打算喝一些咖啡来提高效率(每杯咖啡最多喝一次).他可以按照任何顺序喝咖啡. 泰泰学长喝每杯咖啡会马上喝完并且一滴不剩 (也就是说他不能把一杯咖啡分到两天喝).

当然,泰泰学长的课程作业不能一天写完(至少在现实生活中不能).

我们考虑泰泰学长工作的一些天。 考虑到泰泰学长喝k杯咖啡在这一天并且这写咖啡含有的咖啡因为ai1 , ai2 … aik . 那么第一杯咖啡给他提供了写ai1页的能量, 第二杯给他提供了写max(0 , ai2 - 1)页的能量, 第三杯给他写max(0 , ai3 - 2)页的能量, …,第k杯给他写max(0 , aik - k + 1 )页的能量.

如果泰泰学长在某一天没有喝咖啡,那么他一页都不会写

泰泰学长必须尽快的完成他的课程作业(花费最少的天数去完成). 你的任务是求出泰泰学长能够完成课程作业的最短时间

Input
第一行包含两个数字n , m (1 ≤ n ≤ 2 ⋅ 10^5 , 1 ≤ m ≤ 10^9) — 分别代表咖啡的杯数和要完成的页数.

第二行包含 n 个整数a1 … an (1 ≤ ai ≤ 10^9), ai 表示第i杯咖啡的咖啡因含量.

Output
如果泰泰学长不能完成他的课程作业, 输出-1. 其他情况输出泰泰学长完成任务所需要的最小时间

Examples
输入
5 8
2 3 1 1 2
输出
4
输入
7 10
1 3 4 2 1 4 2
输出
2
输入
5 15
5 5 5 5 5
输出
1
输入
5 16
5 5 5 5 5
输出
2
输入
5 26
5 5 5 5 5
输出
-1
Note
在第一个样例中,泰泰学长第一天可以喝第四杯咖啡(写1 页), 在第二天喝第一杯喝第二杯(写2 + (3 - 1) = 4 页), 第三天喝第五杯咖啡(写 2 页) 同时在第四天喝第三杯咖啡(写1 页) 所以答案是 4 . 显然没有其他方案能够在三天内写完或者用时更少.

在第一个样例中,泰泰学长第一天可以喝第三、四、二杯咖啡(写4 + (2 - 1) + (3 - 2) = 6 页), 在第二天喝第六杯(写4 页)所以答案是 2 . 显然泰泰学长不能够在一天写完.

在第三个样例中,泰泰学长第一天可以喝完所有的咖啡(写5 + (5 - 1) + (5 - 2) + (5 - 3) + (5 - 4) = 15 页).

在第四个样例中,泰泰学长不应该第一天可以喝完所有的咖啡,应该第二天喝其中的一杯咖啡. 所以在第一天泰泰学长写5 + (5 - 1) + (5 - 2) + (5 - 3) = 14 页 第二天写5 页.

在第五个样例中,泰泰学长就算是一天喝一杯咖啡也无法完成课程作业, 所以答案是-1.

题目描述

有n杯咖啡,m页作业,每杯咖啡都有不同的能量,每天喝咖啡的顺序不定,每天第一杯不减,第二杯-1,第三杯-2,依次类推,求最少多少天

思路:二分天数,判断mid天是否能完成作业,我们需要先对咖啡能量进行排序,mid天的第一杯都必须是咖啡能量较大的

比如例1:咖啡能量排序之后为 3 2 2 1 1 假设需要3天喝完,那么
第一天:3 1-1
第二天:2 1-1
第三天:2 0

需要注意,如果该天的咖啡能量为负,那么就max(0, power[j])取较大的!!

代码如下

#include <stdio.h>
#include <iostream>
#include <algorithm>
#define MAX_SZIE 2000050

using namespace std;
typedef long long ll;
int power[MAX_SZIE],m,n;

bool cmp(ll a, ll b)
{
    if(a > b)
        return 1;
    return 0;
}

int check(ll x)
{
    int i,j = 0,flag = 0;	//flag用于判断杯数所要减去的能量
    ll ans = m;
    if(x <= 0)	//如果天数<=0那么就需要区间向右移动
        return 0;
    //如果x天数可以做完作业,那么区间向左移动,判断更少的天数
    while(ans > 0)
    {
        for(i = 1;i <= x;i++)
        {
            ans -= max(0,power[j++] - flag);	//如果能量为负,就取0
            if(j >= n)
                break;
        }
        flag++;
        if(j >= n && ans > 0)	//如果n倍咖啡喝完,还是没有完成作业
            return 0;
    }
    return 1;
}

int main()
{
    int i;
    while(~scanf("%d %d",&n,&m))
    {
        for(i = 0;i < n;i++)
            scanf("%d",&power[i]);
        sort(power, power+n, cmp);
        int l = 0, r = n, mid, ans = -1;
        while(l <= r)
        {
            mid = (l+r) / 2;
            if(check(mid))
            {
                ans = mid;
                r = mid - 1;
            }
            else
                l = mid + 1;
        }
        if(check(ans))//这里需要判断二分得到的天数是否能完成,不能完成就输出-1
            printf("%d\n",ans);
        else
            printf("-1\n");
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值