题目链接:https://ac.nowcoder.com/acm/contest/1577/K
题目大意:
给出n块巧克力,m天吃完。每块巧克力有a[i]快乐值,每天可以选择吃任意块或者不吃巧克力(按照给出的巧克力顺序吃),求如何吃巧克力可以使快乐值的最小值最大。
题解思路:
1.二分最小的开心值。check检查是否有方案可以使得每天的快乐值大于当前的mid,若存在,则答案可以增大,即l = mid + 1。若不存在,则答案减小,即r = mid - 1。
2.对于最后得出来的答案,再进行一次get()函数,得到每块巧克力在第几天被吃。而没有被吃到的巧克力全都在最后一天吃完。
代码如下:
1 #include<stdio.h> 2 typedef long long ll; 3 const int MAXN = 5e4 + 100; 4 5 int n, m, day[MAXN];//n块 m天吃完 6 ll l, r, mid, a[MAXN], ans; 7 8 int check(ll x) //每天都要达到x这么多的开心值 9 { 10 ll sum = 0; //每天的开心值 11 int k = 0; //巧克力编号 12 for(int i = 1; i <= m; i ++) 13 { 14 sum /= 2; //每天都折半 15 while(sum < x) //必须满足该天的开心值大于x 16 { 17 k ++; 18 sum += a[k]; 19 if(k > n) //若无法满足 20 return 0; 21 } 22 } 23 return 1; 24 } 25 26 void get(ll x) 27 { 28 ll sum = 0; 29 int k = 0; 30 for(int i = 1; i <= m; i ++) 31 { 32 sum /= 2; 33 while(sum < x) 34 { 35 k ++; 36 sum += a[k]; 37 day[k] = i; //第k个巧克力在第几天吃 38 } 39 } 40 } 41 42 int main() 43 { 44 scanf("%d%d", &n, &m); 45 for(int i = 1; i <= n; i ++) 46 { 47 scanf("%lld", &a[i]); 48 r += a[i]; 49 } 50 while(l <= r) 51 { 52 mid = (l + r) / 2; 53 if(check(mid)) 54 { 55 l = mid + 1; 56 ans = mid; 57 } 58 else 59 r = mid - 1; 60 } 61 printf("%lld ", ans); 62 get(ans); 63 for(int i = 1; i <= n; i ++) 64 { 65 if(day[i]) 66 printf("%d ", day[i]); 67 else 68 printf("%d ", m); 69 } 70 return 0; 71 }