You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

76 lines
3.6 KiB

2 years ago
#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]>=LkiRk
*/
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使ansans-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;
}