题目概况
题目链接: https://www.luogu.com.cn/problem/P3853
难度: 普及+/提高
题目分析
这题和NOIP2015提高组跳石头非常像,可以练一下这个
涉及知识点: 二分答案
解题思路:
首先提炼几句重点:
1. 相邻路标的最大距离定义为该公路的“空旷指数”。
2. 使得公路的“空旷指数”最小
3. 计算能达到的最小值是多少
4. 起点和终点保证已设有路标
二分答案需要满足有界性和单调性,由题意可知是一段有始有终的公路,满足前者;而题目又明确指出路标递增排列,满足后者。
重点3说明,需要找的值在区间内靠左,若一个解x
是符合题意的可行解,那么x'(x' < x)
都是可行解,只需要在里面继续寻找最优解;若一个解y
是非法解,那么y'(y' > y)
都是非法解。
我们每计算出一个值,都将其看成一个“可行解”,如果在这个“可行解”下,我们增设的路标大于题目中的k
,则“可行解”是非法解。我们可以定义一个check函数
,这个函数对于不同的题有不同的写法,在这个题中,考虑枚举2~n
,如果a[i] - a[i - 1]
的距离大于mid
,那么就与当前“可行解”相矛盾,需要增设。值得注意的是,如果此子区间长度正好是mid
的倍数,则会与a[i]
的路标重合,需要减1.(小学奥数)
倡导读题面时把关键句段写到程序注释中。
代码拆解及要点分析
无。
完整代码
#include <iostream>
#include <cstdio>
using namespace std;
/*
相邻路标的最大距离定义为该公路的“空旷指数”。
使得公路的“空旷指数”最小
计算能达到的最小值是多少
起点和终点保证已设有路标
起点是0,终点是l
*/
const int MAXN = 1e5 + 5;
int l, n, k, ans; //公路的长度;原有路标的数量;最多可增设的路标数量
int a[MAXN];
bool check(int x) {
int tot = 0; //最多设置的路标数
for (int i = 2; i <= n; i++) {
if (a[i] - a[i - 1] >= x) {
tot += (a[i] - a[i - 1])/x;
if ((a[i] - a[i - 1]) % x == 0) {
tot--;
}
}
}
if (tot > k) {
return false;
}
return true;
}
int main() {
cin >> l >> n >> k;
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
int left = 1, right = l;
while (left <= right) {
int mid = (left + right) / 2;
if (check(mid)) {
ans = mid;
right = mid - 1;
} else {
left = mid + 1;
}
}
cout << left << endl;
return 0;
}