P2678 [NOIP2015 提高组] 跳石头
大致题意
从距离为\(L\)的起点到终点,其中有\(N个\)岩石,然后想要使最短跳跃距离最大化,最多可以移走\(M\)块岩石
解题思路
最初看到题时,会从题目出发,计算岩石的最短距离,然后进行更新
但是直接模拟的方法太笨了
可以转换一下思路,假设我们在寻找到当前石头距离不小于\(k的石头,如果遇到距离小于k的石头,就把它移走\),那么这样就比较好理解了
\(我们只需要维护一个k,即为最短跳跃距离,只要使这个k尽可能大且移走石块数量不超出M,即为答案\)
具体实现
题目中有一个关键词,是整数二分出现时题目中经常会出现的用词:最短跳跃距离的最大值
整数二分经常在有类似'最大化最小值',或者是'最短距离的最大值'这样字眼的题目中出现。
这里用到了整数二分的计算方法,左边界\(l\)的值可以设成0,右边界\(r\)的值可以设为起点到终点的总距离,然后进行二分
\(检查过程则是设定一个距离x,从起点开始跳跃。如果第i个石头和当前石头距离小于x,则移走第i个石头,否则跳跃到第i个石头上\)
\(最后再用总共移走的石头数量和M比较,看当前结果是否合法\)
为了格式的严整,这里把检查过程写入一个函数check(int x)里
二分代码模板:
// l, r, ans已定义且l, r已被合理赋值
while(l <= r){
int mid = l + r >> 1;
if(check(mid)){
ans = mid;
l = mid + 1;
} else r = mid - 1;
}
// output ans
代码实现
// P2678 (NOIP2015 提高组) - 跳石头
// 6 Mar 2021 by zqsml
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 50010;
int len, n, m;
int rock[N];
bool check(int num){
int ind, cur;
ind = 0, cur = 0;
int count = 0;
while(ind < n + 1){
ind ++ ;
if(rock[ind] - rock[cur] < num) count ++ ;
else cur = ind;
}
if(count > m) return false;
return true;
}
int main(){
scanf("%d %d %d", &len, &n, &m);
for(int i = 1; i < n + 1; i ++ ) scanf("%d", &rock[i]);
rock[n + 1] = len;
int ans = 0;
int l = 0, r = len;
while(l <= r){
int mid = l + r >> 1;
if(check(mid)){
ans = mid;
l = mid + 1;
}
else r = mid - 1;
}
printf("%d\n", ans);
return 0;
}

浙公网安备 33010602011771号