Loading

CF1066D 题解

CF1066D

题意

\(n\) 个物品和 \(m\) 个盒子,每个盒子最开始都是空的,大小为 \(k\)。物品依次编号为 \(1, 2 \dots n\),第 \(i\) 件物品的大小为 \(a_i\)

现在需要把物品装进盒子里,做以下操作:取出一个空盒子,从左到右遍历物品,如果第 \(i\) 件物品可以放进当前盒子,就放进去,盒子大小减少 \(a_i\),否则,重复这个操作。

现在像打包尽可能多的物品,为了达到目标,可以丢弃最左边的一些物品。

请你求出最多可以装多少个物品。

思路

首先,这个题目有一个很重要的点:读清楚题目!!!

其实可以抽象成这样一个模型:将一个序列分成若干段,每一段的和要小于等于 \(k\),并且尽可能使得分出来的段数最小。

那么,假设丢弃了前 \(x\) 个物品,且剩下的物品可以放在 \(m\) 个盒子里,那么说明丢弃前 \(x + 1\) 个物品,剩下的物品也可以放在 \(m\) 个盒子里。

所以,这道题具有 单调性,可以二分,时间复杂度为 \(O(n \times \log n)\)


但是,这道题目有没有时间复杂度更优的做法呢?当然有,贪心

因为要丢弃的是一段前缀,那么我们能不能考虑倒着做呢?

既然要考虑倒着做,那么我们就得先证明出正着做和倒着做所得到的分段数是一样的。

假设序列的某一个后缀正着做的答案为 \(ans1\),倒着做的答案为 \(ans2\)

  1. 先正着做,得到的答案为 \(ans1\),而再倒过来做不会使得原先的分界线向左移动,所以 \(ans2 \le ans1\)
  2. 先倒着做,得到的答案为 \(ans2\),而再正过来做不会使得原先的分界线向右移动,所以 \(ans1 \le ans2\)

所以,\(ans1 = ans2\)

posted @ 2023-03-12 22:32  chengning0909  阅读(24)  评论(0编辑  收藏  举报