鏈接:P2985
題目描述
Bessie拿到了N (1 <= N <= 50,000)塊巧克力。她決定想個辦法喫掉這些巧克力,使得它在喫巧克力的這段時間裏,最不開心的一天儘可能的開心。並且一共喫D (1 <= D <= 50,000)天。
每塊巧克力有一個開心值H_i (1 <= H_i <= 1,000,000),當某天你喫下那塊巧克力時,你將獲得那塊巧克力的開心值。每一天的開心值是所有當天喫掉的巧克力的總開心值之和。每天晚上Bessie睡覺之後,它的開心值會減半。也就是說,比如昨天Bessie的開心值爲50,那麼今天早上我一醒來我就會有25點的開心值,捨去小數點後數字。另外,Bessie還有一個怪癖,她喜歡按照巧克力本來的排列順序喫。
Bessie第一天的開心值爲0,求一個每天喫巧克力的方案,使得Bessie最不開心的一天儘可能的開心。
輸入格式
-
Line 1: Two space separated integers: N and D
-
Lines 2…N+1: Line i+1 contains a single integer: H_i
輸出格式
-
Line 1: A single integer, the highest Bessie’s minimum happiness can be over the next D days
-
Lines 2…N+1: Line i+1 contains an integer that is the day on which Bessie eats chocolate i
輸入輸出樣例
輸入 #1
5 5
10
40
13
22
7
輸出 #1
24
1
1
3
4
5
(輸入第2到N+1行是每塊巧克力的快樂值
輸出第一行是每天得到的快樂值,2到N+1行是第i塊巧克力在第幾天被喫)
一看到題目顯然易見得是二分答案,但是我一直都調不過去。
還好今天早上有大佬在機房講解了這道題才讓我略懂一二,把這道題過了。
我們二分每天得到的快樂值的大小,判斷這個快樂值如果把巧克力都吃了都得不到則縮小範圍,否則就儘可能將這個快樂值放大。
在每一次二分判斷是否符合條件的時候,如果符合條件就可以先把此時每塊巧克力喫的天數給用數組存儲起來了。
但是明明是黃題的難度爲什麼會被升到藍題呢?
因爲其中有很多的坑點,如果簡單地把這道題按照這個思路打出來不考慮一些特殊情況和細節方面,很難可以ac(沒錯我又看了題解才A的
看一下代碼再慢慢說坑點:
代碼:
#include <cstdio>
#include <iostream>
#define LL long long
using namespace std;
LL n,m,d[100001],a[100001],ans;
int check(LL x)
{
LL sum=0,k=0;
for (LL i=1;i<=m;i++) //枚舉天數
{
sum/=2; //第一個坑點: 每天一起牀快樂值減半
while (sum<x) //一直喫巧克力直到喫的巧克力所得到的快樂值大於當前二分得到的每天快樂值
{
k++;
sum+=a[k];
if (k>n) //如果當前設定的這個每天的快樂值太大,無法達到就要縮小範圍
return 0;
if(x&&x==ans) d[k]=i; //在二分尋找的答案的過程中隨時更新巧克力喫的時間
}
}
return 1;
}
int main()
{
LL L=0,R=0,mid;
scanf("%lld%lld",&n,&m);
for (LL i=1;i<=n;i++)
scanf("%lld",&a[i]),R+=a[i]; //R的最大值,即二分的右邊界
while (L<=R)
{
mid=(L+R)/2;
if (check(mid))
ans=mid,L=mid+1;
else
R=mid-1;
}
printf("%lld\n",ans);
check(ans); //第二個坑點:找到最優答案後要再掃一遍更新一下d數組,因爲如果不掃一遍的話day[]的值可能還會停留在上一階段。
for (LL i=1;i<=n;i++)
{
if (d[i]>0)
printf("%lld\n",d[i]);
else
printf("%lld\n",m); //第三個坑點:題目要求的蜜汁字典序,所以沒喫掉的要在最後一天全喫完
}
return 0;
}