算法入门-二分答案-整点巧克力?

整点巧克力

https://ac.nowcoder.com/acm/contest/22353/1003

题意

  • 给定n块巧克力d天,第i块巧克力提供热量ai,每天热量会减半
  • 请给出最大的最小热量,使得在d天中每天的热量值都大于等于最小热量

思路

  • 观察可得,最小热量越大维持天数越小,满足单调性,二分最小热量,对每一个最小热量判断是否足够维持d天
  • 注意各种细节

细节(狂WA9发,人已经麻啦)

  • 虽然每一块巧克力都是2e5以内的范围,但加和可能超过int——不开long long见祖宗
  • 左右界:在本题中左界似乎不影响,但是右界得设的足够大如1e16,所以建议以后考虑二分的时候把右界算出来,在这个题中右界为所有热量值的加和
  • 特殊情况思考,维护最后的吃巧克力顺序时,有可能有的巧克力吃了也不会增加天数,所以在judge中会以没吃的形式存在,所以输出顺序的时候,要把这些补到最后一天吃
  • 本题其实不用在judge中判断每一种情况吃完后能维护多少天然后再和d比较,这样会增加很多细节,比如天数超过d天,顺序无法直接放,以及吃完后还能满足若干天,然后把这若干天补充到判断中
  • 更为高效的方法其实是直接模拟吃d天,只要有一天不够吃,直接return 0 ,如果能维持d天多出来的就都放到最后一天吃

随感

  • 今天是不适合敲代码的一天,昨天回本部打了场选拔赛,好几个题开了都没写AC,幸亏是IOI赛制,还能捞点部分分,仔细想来昨天的二分似乎也是细节不太合理,以及广搜的思路不对,说白了还是菜,还得多练TT

AC代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
int h[2020202]; 
int t[2020202];
int n,d;

bool judge(int p){
	long long sum=0;
	int cnt=1;
    for(int i=0;i<d;i++){
        while(sum<p&&cnt<=n){
            sum+=h[cnt++];
        }
        if(sum<p)return 0;
        sum/=2;
    }
    return 1;
}
void eat(int e){
	long long sum=0;
	int cnt=1;
    for(int i=0;i<d;i++){
        while(sum<e&&cnt<=n){
            sum+=h[cnt++];
            printf("%lld\n",i+1);
        }
        sum/=2;
    }
    while(cnt<=n){
        printf("%lld\n",d);
        cnt++;
    }
}
signed main(){
	int l=1,r=0;	
	scanf("%lld%lld",&n,&d);
	for(int i=1;i<=n;i++){
        scanf("%lld",&h[i]);
      	r+=h[i];
    }

	while(l<=r){
		int mid=(l+r)>>1;
		if(judge(mid)){
			l=mid+1;
		}else{
			r=mid-1;
		}
	}
	printf("%lld\n",l-1);
    eat(l-1);
	return 0;
}
全部评论

相关推荐

评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务