|
|
#include <bits/stdc++.h>
|
|
|
using namespace std;
|
|
|
const int N = 500010;
|
|
|
|
|
|
typedef long long LL;//五年OI一场空,不开LONG LONG
|
|
|
int n, d, k; // n:格子数,d:机器人可以跳的距离,k:想要取得的分值
|
|
|
int x[N], w[N]; // 距离数组x[i]表示i号格子距离出发点的距离,w[i]从i号格子中可以获得的分值
|
|
|
|
|
|
LL f[N]; // f[i]:到达i点时可以获取到的最大分值
|
|
|
int q[N]; // 单调队列,记录的是格子号
|
|
|
|
|
|
bool check(int g) { // g 描述的是给定的金币数量
|
|
|
LL res = 0;
|
|
|
|
|
|
// 多次dp,每次需要清空统计数组
|
|
|
memset(f, -0x3f, sizeof f); // 预求最大,先设最小
|
|
|
f[0] = 0; // 递推起点数据,分值为0,这个要先看状态转移方程,再思考整体初始化、起点初始化
|
|
|
int hh = 0, tt = -1;
|
|
|
|
|
|
// L,R : 左右边界
|
|
|
int L = max(1, d - g), R = d + g;
|
|
|
|
|
|
/*
|
|
|
④ 为什么要先处理入队列,再处理出队列?反过来为什么是错的呢?
|
|
|
答:我们向单调队列中添加节点的逻辑是发现x[i]-x[k]>=L,也就是k没有进过队列,没有参加
|
|
|
评比过,并且,两个格子间的距离大于了L,就让它进来试试。
|
|
|
|
|
|
但是,这样就真的可以了吗?因为我们知道,单调队列中保存是一个个格子号,而这些格子号必须在i左侧指定的范围内才行。
|
|
|
x[i]-x[k]>=L是成立了,那会不会k离i太远了,超过了上限R呢?如果是这样的话,那么k是不能停留在队列中的,需要去除掉。
|
|
|
*/
|
|
|
for (int i = 1, j = 0, k = 0; i <= n; i++) {
|
|
|
// ① 新元素入队列
|
|
|
while (x[i] - x[k] >= L) { // i走的挺快,k有资格参评了
|
|
|
while (hh <= tt && f[q[tt]] <= f[k]) tt--; // 年龄比k大,值比k小的都去死
|
|
|
q[++tt] = k++; // k入队列
|
|
|
}
|
|
|
|
|
|
// ② 越界元素出队列
|
|
|
while (x[i] - x[j] > R) j++; // j出界,j无法跳到i
|
|
|
while (hh <= tt && q[hh] < j) hh++; // j都出界了,单调队列也需要维护,把比j小的都干掉
|
|
|
|
|
|
// ③ 队列非空,队列头中保存的就是前面[L,R]范围内的分数最大值所对应的y号格子
|
|
|
if (hh <= tt) f[i] = f[q[hh]] + w[i]; // 再加上i号格子中的w[i]分值,就是总分值
|
|
|
|
|
|
// 时刻更新最大值
|
|
|
res = max(res, f[i]);
|
|
|
}
|
|
|
|
|
|
// 因为分值中存在负数,一旦是在半途中出现可以获取到的分值大于等于k时,就可以停止掉,表示已经找到了一个金币数量满足增加了自由度后,可以取得k这样的分值
|
|
|
return res >= k;
|
|
|
}
|
|
|
|
|
|
int main() {
|
|
|
// 加快读入
|
|
|
ios::sync_with_stdio(false), cin.tie(0);
|
|
|
cin >> n >> d >> k; // 格子数量,机器人每次可以跳的距离,想要拿到的分数
|
|
|
for (int i = 1; i <= n; i++) cin >> x[i] >> w[i]; // 起点到第i个格子的距离,第i个格子的分数
|
|
|
|
|
|
int L = 0, R = 1e9, ans = -1; // 二分的左右无脑边界值
|
|
|
/*
|
|
|
二分的最后结果有两种方式:
|
|
|
1、使用ans变量记录最终结果,ans初始化为-1,每次找到check()通过的mid,ans=mid,这样,如果最终有答案ans就记录的是答案,否则就记录的是-1。
|
|
|
2、不使用ans变量记录,而是最后再用!check(L)然后输出-1。
|
|
|
个人认为方法1更易理解。
|
|
|
*/
|
|
|
while (L < R) {
|
|
|
int mid = L + R >> 1;
|
|
|
if (check(mid)) {
|
|
|
R = mid;
|
|
|
ans = mid;
|
|
|
} else
|
|
|
L = mid + 1;
|
|
|
}
|
|
|
printf("%d\n", ans);
|
|
|
return 0;
|
|
|
} |