'commit'
This commit is contained in:
70
TangDou/CSP-J/AcWingTraining/T7/472_2.cpp
Normal file
70
TangDou/CSP-J/AcWingTraining/T7/472_2.cpp
Normal file
@@ -0,0 +1,70 @@
|
||||
#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;
|
||||
}
|
||||
Reference in New Issue
Block a user