题目:

贝西从公牛那里收到了 N (1 <= N <= 50,000) 巧克力,但不想吃得太快,所以她想计划下一个 D (1 <= D <= 50,000) 天的巧克力吃时间表,以便在这些日子里最大限度地提高她的最低幸福水平。 Bessie 的幸福感是一个整数,从 0 开始,并在她睡觉时在一夜之间减半(必要时四舍五入)。然而,当她吃巧克力 i 时,她的幸福感会增加整数 𝐻 我 H 我 ​ (1 <= 𝐻 我 H 我 ​ <= 1,000,000)。如果她在某一天吃巧克力,那么她当天的幸福感就被认为是她吃完巧克力后的幸福程度。贝西坚持要按照收到的顺序吃巧克力d 他们。 如果存在多个最优解,请打印其中任何一个。 考虑在 5 天内吃掉 5 块巧克力;它们分别带来幸福(10、40、13、22、7)。 如果贝西在第一天吃了第一块巧克力(10 幸福),然后等着吃其他巧克力,那么第一天之后她的幸福度是 10。

前言与题解35一样,依旧是一道最值问题,并且固定量比较多(天数,吃巧克力的个数及顺序),考虑二分枚举,然后去验证

Line 1: Two space separated integers: N and D

第 2到N+1 行:第 i+1 行包含一个整数,该整数是 Bessie 吃巧克力 i 的那一天 的心情增加值

思路&AC代码:

#include<iostream>
#include<cstring>//memset()
#define int long long//二分枚举中,如果第一天就把所有巧克力吃完了,可达5e10,超过了2e9
using namespace std;
int chocolate[50010];//各个巧克力能加的心情
int n,d,cnt;//巧克力个数,天数,当前吃的个数
int eat[50010];//存储第几天吃了多少块
bool solve(int happy)
{
    int curhappy=0;
    cnt=1;
    int i;
    for(i=1;i<=d;++i)
    {
        while(curhappy<happy)//每一天的初始心情值(前一天吃完/2)不够假设的最大的最低心情值就吃巧克力(有顺序要求) 
        {
            if(cnt>n) {return false;}//一上来就判断,防止多操作
            curhappy+=chocolate[cnt];
            ++eat[i];
            ++cnt;
        }
        curhappy>>=1;// /=2
    }
    return true;//中间的cnt>n已经判断过了,这里必然cnt<=n && curhappy>=happy 
}
signed main()//写完了才想起把int改long long,就要这么写main
{
    ios::sync_with_stdio(0);cin.tie(0);
    int sum=0;//记录下能够达到的最大心情值(一天全吃完)
    cin>>n>>d;
    for(int i=1;i<=n;++i)
    {
        cin>>chocolate[i];
        sum+=chocolate[i];
    }
    int l=0,r=sum,mid=(l+r+1)>>1;//我习惯这么写,这样写只要在找最大值时写成(l+r+1)就行
    while(l<r)
    {
        if(solve(mid)) {l=mid;}
        else{r=mid-1;}
        mid=(l+r+1)>>1;
    }
    memset(eat,0,sizeof(eat));//清空eat,留给后面重新计算
    solve(l);//这里重新算有两个原因.一是eat已经乱了(也可以增加一个标记值判断是不是最后一次计算,决定每次记不记录eat。二是若最后一次l+1==r时,mid=r,如果solve(r)不服题意,则r=mid-1 ==l,最后一次记的eat是l+1(r)的,而solve(r)不符题意,答案不正确,需要调用正确的solve(l)
    cout<<l<<'\n';
    for(int j=1;j<=d;++j)
    {
        while(eat[j]!=0) {cout<<j<<'\n';--eat[j];}//eat[j]是几就输出几次
    }
    for(int i=cnt;i<=n;++i) {cout<<d<<'\n';}//最后满足要求的一次多了一个++cnt。题目要求巧克力全吃完,所以剩下的全放最后一天吃就好。因为此时答案已经不能再增加了(二分枚举得出的结果),所以剩下的巧克力什么时候吃都行
    return 0;
}