题目传送门:P2678 [NOIP2015 提高组] 跳石头
题解
这道题目明显就是要用二分答案来求。题目中说“即最短跳跃距离的最大值。”看到最短距离最大
化,就说明我们的二分答案就要登场了.
二分答案
平时我们解决问题一般是求解,但还有一种叫做试解,其中就有二分试解.但是,二分答案是有限制的!所求序列必须具有单调性。二分答案的时间复杂度约为 Θ ( l o g n ) . \Theta(logn). Θ(logn).
left, right, mid
可以编写一个check函数来判断当前解是不是正解.如果是正解
那么就去右半区查询.为什么?因为这个序列本身是递增的而且
题目要求最大的值,所以当然要去右半区找.
否则就去左半边找,为什么?
这个数组本来就是递增的,有因为当前解不是正解,所以比它大的值
也不可能是正解,那么只能去左半边找的.
注意事项
切记! a n a_n an 并不是终点,所以要把 a n + 1 a_{n+1} an+1 的值设为 l l l.
代码
#include<bits/stdc++.h>
using namespace std;
int l, n, m, a[500005], ans;
bool check(int x) {
// cnt:移走石块数目 i:下一块石头的编号 now:当前石头编号
int cnt = 0, i = 0, now = 0;
while (i < n + 1) { // n不是终点!
i++;
if (a[i] - a[now] < x) // 如果当前值小于mid
cnt++; // 把它移走
else
now = i; // 否则先走过来
}
if (cnt > m) return 0; // 如果搬多了,那么说明它不是正解
else return 1;
}
int main() {
// freopen("stone.in", "r", stdin);
// freopen("stone.out", "w", stdout);
ios::sync_with_stdio(false);
cin.tie(0);
cin >> l >> n >> m;
for (int i = 1; i <= n; i++)
cin >> a[i];
a[n+1] = l; // a[n]不是终点
int le = 1, ri = l; // 左边为1,右边为l
while (le <= ri) { // 二分标准循环
int mid = (le + ri) / 2; // 计算mid值
if (check(mid)) { // 是否是正解
ans = mid; // 是的话,更新答案
le = mid + 1; // 去找右半边有没有更好的答案
}
else
ri = mid - 1; // 否则去左半边找
}
printf("%d", ans);
return 0;
}

810

被折叠的 条评论
为什么被折叠?



