携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第8天,点击查看活动详情
LCP 12. 小张刷题计划
为了提高自己的代码能力,小张制定了 刷题计划,他选中了 题库中的 道题,编号从到 ,并计划在 天内按照题目编号顺序刷完所有的题目(注意,小张不能用多天完成同一题)。
在小张刷题计划中,小张需要用 的时间完成编号 的题目。此外,小张还可以使用场外求助功能,通过询问他的好朋友小杨题目的解法,可以省去该题的做题时间。为了防止“小张刷题计划”变成“小杨刷题计划”,小张每天最多使用一次求助。
我们定义 天中做题时间最多的一天耗时为 (小杨完成的题目不计入做题总时间)。请你帮小张求出最小的 是多少。
示例 1:
输入:time = [1,2,3,3], m = 2
输出:3
解释:第一天小张完成前三题,其中第三题找小杨帮忙;第二天完成第四题,并且找小杨帮忙。
这样做题时间最多的一天花费了 3 的时间,并且这个值是最小的。
示例 2:
输入:time = [999,999,999], m = 4
输出:0
解释:在前三天中,小张每天求助小杨一次,这样他可以在三天内完成所有的题目并不花任何时间。
数据范围
1 <= time.length <= 10^51 <= time[i] <= 100001 <= m <= 1000
思路
题目要求 尽可能小。
考虑这样一个问题,什么时候 的满足情况的?
设当 当前为 , 且满足可以在天内完成。
显然, 都是满足这一条件的
若是 为最后答案,则一定满足如下条件:
小于的一定不满足在天内完成,大于等于的值一定满足条件
所以根据条件可以把整个 集合划分为两部分
对于区间被分成两部这种情况,要找到中间的分界点。
我们可以采用二分去逐步逼近
下一个问题,如何检查的合法性?
我们由于只能顺序的完成任务,那么这就给我们可操作空间比较小
只需要顺序的贪心完成就可以了。
注意,“今天“ 内可以完成很多件任务,可以消去耗时最高的一件任务,而不一定是最后一件任务。
代码
class Solution {
public:
int minTime(vector<int>& time, int m) {
int l = 0, r = 1 << 30;
int tiki = 0;
while (l < r) {
int x = l + r >> 1;
int cnt = 1, cur = 0, ma = 0, tot = 1;
for (int i = 0; i < time.size();) {
int v = time[i];
if (cur + v <= x) {
cur += v;
ma = max(ma, v);
i ++;
} else {
if (tot) {
if (v > ma) {
tot = 0;
i ++;
} else {
tot --;
cur -= ma;
}
} else {
cur = 0;
ma = 0;
tot = 1;
cnt ++;
}
}
}
if (cnt <= m) r = x;
else l = x + 1;
}
return l;
}
};