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.

70 lines
2.3 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 500010;
LL dist[N], w[N], f[N]; // 五年OI一场空不开long long见祖宗
int n, d, k;
// 检查花费g个金币进行改造后最高得分是否会超过k
bool check(int gold) {
// 机器人能够弹跳的范围[L,R]
int L = max(1, d - gold);
int R = d + gold;
// 注意:这里要初始化为负无穷
memset(f, 0xc0, sizeof f);
f[0] = 0;
for (int i = 1; i <= n; i++) {
// 从i的前一个格子开始枚举到起点
for (int j = i - 1; j >= i - R; j--) {
// 剪枝机器人从j号格子加上R还是法到达i号格子
// 那么从j号格子之前的格子也无法到达i号格子
if (dist[j] + R < dist[i]) break;
// 机器人从j号格子加上L还是超过了i号格子
// 那么继续尝试j号之前的格子
if (dist[j] + L > dist[i]) continue;
// 机器人从j号格子可以转移到i号格子
f[i] = max(f[i], f[j] + w[i]);
if (f[i] >= k) return true;
}
}
return false;
}
int main() {
// 加快读入
ios::sync_with_stdio(false), cin.tie(0);
cin >> n >> d >> k;
for (int i = 1; i <= n; i++) cin >> dist[i] >> w[i];
/*
二分金币的数量
二分时候左右端点是什么?
由于我们点的个数是500000个要求分数的范围是[1,1e9]机器人初始时是2000的弹跳距离
那么再结合我们花费金币后机器人弹跳范围,我们想要金币花费最少,假设每个点都得走过,
分数和才能达到最值那么我们计算下来需要花费的平均金币数为2000但实际上由于每个点的
分数分布不均匀并且并不需要每一个点都经过所以我们二分可以将左边界设为0右边界设
为2010。
*/
int L = 0, R = 2010, ans = -1;
while (L < R) {
// 所有满足条件的情况都在mid的右边区间
// 搜索右边区间最小值
// 适用二分搜索模板1
int mid = L + R >> 1;
if (check(mid)) {
ans = mid;
R = mid;
} else
L = mid + 1;
}
cout << ans << endl;
return 0;
}