题目传送门

二分 + 滑动窗口

1、给定某个长度,若该长度满足条件,就变长继续观察,不满足则变短继续观察,直到找到最小符合的长度值,因此使用二分

2、\(check\)函数中,给定最长的空题段的长度是\(mid\),求出满足题意的花费时间最小值\(res\),判断\(res <= t\)是否成立

3、由于最长的空题段的长度是\(k = mid\),传进\(check()\)函数的变量是\(k\),因此滑动窗口的长度是\(mid + 1\),

以\(i\)结尾的\(f[i]\),滑动窗口的区间是\([i - (k + 1),i - 1]\),单调队列维护的是该区间的最小值,由于滑动窗口不包含\(i\),因此\(f[i]\)需要在\(while\)上方进行更新。

AcWing 1090. 绿色通道_最小值

#include <bits/stdc++.h>

using namespace std;
const int N = 50010;
const int INF = 0x3f3f3f3f;

int n, m;
int w[N];
int f[N], q[N];

bool check(int limit) {
int hh = 0, tt = 0;
for (int i = 1; i <= n; i++) {
//画图理解一下这个滑动窗口的大小
if (q[hh] < i - limit - 1) hh++;

f[i] = f[q[hh]] + w[i];

while (hh <= tt && f[q[tt]] >= f[i]) tt--;//保留怒气最小值
q[++tt] = i;
}

int res = INF;
for (int i = n - limit; i <= n; i++) res = min(res, f[i]);
return res <= m;
}

int main() {
cin >> n >> m;
for (int i = 1; i <= n; i++) cin >> w[i];
//二分
int l = 0, r = n;
while (l < r) {
int mid = (l + r) >> 1;
if (check(mid)) r = mid;
else l = mid + 1;
}
printf("%d\n", l);
return 0;
}