AcWing 154. 滑动窗口(双端队列版)大佬如何优化?
原题链接
简单
#include <iostream>
#include <cstring>
#include <algorithm>
#include <deque>
using namespace std;
typedef long long LL;
const int N = 500010;
int n, d, k;
int x[N], w[N];
LL f[N];
bool check(int mid)
{
int l = max(1, d - mid), r = d + mid;
LL res = 0;
deque<int> dq; // 使用 deque 代替手动维护的单调队列
memset(f, -0x3f, sizeof f);
f[0] = 0;
for (int i = 1, j = 0, k = 0; i <= n; i++)
{
// 更新队列:确保窗口的左边界 >= l
while (x[i] - x[k] >= l)
{
while (!dq.empty() && f[dq.back()] <= f[k])
dq.pop_back();
dq.push_back(k++);
}
// 移动 j,确保窗口的右边界 <= r
while (x[i] - x[j] > r) j++;
// 移除过期的元素
while (!dq.empty() && dq.front() < j)
dq.pop_front();
// 如果队列非空,则更新 f[i]
if (!dq.empty())
f[i] = f[dq.front()] + w[i];
// 更新结果
res = max(res, f[i]);
}
return res >= k;
}
int main()
{
scanf("%d%d%d", &n, &d, &k);
for (int i = 1; i <= n; i++)
scanf("%d%d", &x[i], &w[i]);
int l = 0, r = 1e9;
while (l < r)
{
int mid = (l + r) >> 1;
if (check(mid)) r = mid;
else l = mid + 1;
}
// 边界检查
if (!check(r)) r = -1;
printf("%d\n", r);
return 0;
}