欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

吃糖【二分】

程序员文章站 2024-03-17 16:43:28
...

题目描述

Bessie有N(1N50,000)N(1≤N≤50,000)颗糖果,编号1N1-N,但她不打算马上吃光,而是计算在接下来的D(1D50,000)D(1≤D≤50,000)天按糖果编号从小到大逐天吃,当然,BessieBessie以一天连续吃多颗糖果,也可以不吃,但不能跳着糖果来吃,要按糖果顺序吃。
吃了糖果i,BessiesBessie's的能量值会增加Hi(1Hi1000,000)H_i(1≤H_i≤1,000,000)BessieBessie都是在白天吃糖果,然后晚上睡觉,第二天醒来,她的能量值会变成前一天的能量值的一半(向下取整)。BessiesBessie's的能量值会累加。请你决定第i颗糖果应该是第几天吃,才能使得BessieBessie在这D个晚上里,能量值最小的那个晚上(假设是第x个晚上),第xx个晚上的能量值最大?输出该值,并且输出第1(1iN)1(1≤i≤N)颗糖果是Bessie第几天吃掉的。
例如:有5个糖果,能量值分别是:(104013227)(10,40,13,22,7)。
BessieBessie按以下方式吃糖果,将会得到最优值:
第几天 醒来时能量值 吃了糖果后能量值 晚上睡觉能量值
1 0 10+40 50
2 25 ----- 25
3 12 13 25
4 12 22 34
5 17 7 24
可以看出,第1天吃了糖果1、糖果2,第2天不吃糖果,第3天吃了糖果3,第4天吃了糖果4,第5天吃了糖果5。那么在这5个晚上,能量值最低的是第5个晚上,能量值是24,所以输出24。然后你还要输出第1(1iN)1(1≤i≤N)颗糖果是BessieBessie第几天吃掉的。

输入

第1行:两个整数:NDN和D
2N+12-N+1行:每行一个整数HiH_i.

输出

第l行:一个整数,在这DD个晚上里,能量值最小的那个晚上(假设是第XX个晚上),第xx个晚上的能量值最大可以是多少?
2N+12-N+1行:每行一个整数,第i行表示第i颗糖果是第几天被吃的。

样例输入

5 5
10
40
13
22
7

样例输出

24
1
1
3
4
5

题解:

本题可以用二分答案去解决。当我们知道答案后,贪心地去吃糖果,从左往右扫描糖
果,如果当前的能量没有达到答案,那么必须把当前的那颗糖果吃掉,如果当前的能量已
经达到了答案,那么当天没有必要再吃当前的那颗糖果,留着第二天吃更好。如此扫描下
去,看最后能维持的天数是否达到题目给出的天数d,如果达到,则是可行的,否则是不可行。时间复杂度是O(NlogN)。

#include <bits/stdc++.h> 
#define ll long long
using namespace std; 
const int N=50100;
ll c[N];
int a[N],n,d;
int check(ll x,int flag)
{
    int k=0;
    ll now=0;   
    for(int i=1;i<=d;i++)
    {
        now/=2;
        while(now<x&&k<=n)
        {
            k++;
            if(flag)a[k]=i;
            now+=c[k];
        }
        if(now<x) return 0;
    }
    if(flag)
        for(int i=k+1;i<=n;i++)a[i]=d;
    return 1;
}
int main()
{
    ll ans=0,l=0,sum=0;
    scanf("%d%d",&n,&d);
    for(int i=1;i<=n;i++)
    {
        scanf("%lld",&c[i]);
        sum+=c[i];
    }
    while(l<=sum)
    {
        ll mid=(l+sum)/2;
        if(check(mid,0))
        {
            ans=mid;
            l=mid+1;
        }
        else sum=mid-1;
    }
    printf("%lld\n",ans);
    check(ans,1);  
    for(int i=1;i<=n;i++)
        printf("%d\n",a[i]);
    return 0;
}
相关标签: 二分