例题如下:
P2678 [NOIP2015 提高组] 跳石头
题目背景
一年一度的“跳石头”比赛又要开始了!
题目描述
这项比赛将在一条笔直的河道中进行,河道中分布着一些巨大岩石。组委会已经选择好了两块岩石作为比赛起点和终点。在起点和终点之间,有 N 块岩石(不含起点和终点的岩石)。在比赛过程中,选手们将从起点出发,每一步跳向相邻的岩石,直至到达终点。
为了提高比赛难度,组委会计划移走一些岩石,使得选手们在比赛过程中的最短跳跃距离尽可能长。由于预算限制,组委会至多从起点和终点之间移走 M 块岩石(不能移走起点和终点的岩石)。
输入格式
第一行包含三个整数 L,N,M,分别表示起点到终点的距离,起点和终点之间的岩石数,以及组委会至多移走的岩石数。保证 L≥1 且 N≥M≥0。
接下来 N 行,每行一个整数,第 i 行的整数 Di(0<Di<L), 表示第 i 块岩石与起点的距离。这些岩石按与起点距离从小到大的顺序给出,且不会有两个岩石出现在同一个位置。
输出格式
一个整数,即最短跳跃距离的最大值。
输入输出样例
输入 #1
25 5 2 2 11 14 17 21输出 #1
4说明/提示
输入输出样例 1 说明:将与起点距离为 2和 14 的两个岩石移走后,最短的跳跃距离为 4(从与起点距离 17 的岩石跳到距离 21 的岩石,或者从距离 21 的岩石跳到终点)。
另:对于20%的数据,0 ≤ M ≤ N ≤ 10。
对于50%的数据,0 ≤ M ≤ N ≤ 100。
对于100%的数据,0 ≤ M ≤ N ≤ 50000,1 ≤ L ≤ 1000000000。
对于该题,其实就用二分答案就可以了。具体操作是给定足够范围的(l,r),然后根据当前所处石头位置和与下一个石头的距离每隔一个mid的距离放一块石头然后计数s(注意不要和原有石头重合,距离不足一个mid或者等于一个mid直接跳入下一块石头),最后当s小于给定的石头数m时说明mid过大,往左区间继续二分;s大于m时,mid过小,往右区间继续二分。
AC代码(全新的二分模板):
#include<bits/stdc++.h>
#include<unordered_set>
#include<utility>
#define mem(a,b) memset(a,b,sizeof a)
#define cinios (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0))
#define sca scanf
#define pri printf
#define ul u << 1
#define ur u << 1 | 1
//#pragma GCC optimize(2)
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 1010, M = 100010;
int INF = 0x3f3f3f3f, mod = 100003;
ll LNF = 0x3f3f3f3f3f3f3f3f;
int main()
{
cinios;
int l, n, m, a[50050], s, now, left, right, mid, ans;
cin >> l >> n >> m;
for (int i = 1; i <= n; i++)
{
cin >> a[i];
}
left = 0, right = l;
while (left <= right)
{
mid = (left + right) / 2;
s = 0, now = 0;
for (int i = 1; i <= n; i++)
{
if (a[i] - a[now] < mid)
s++;
else
now = i;
}
if (s <= m)
{
left = mid + 1; ans = mid;
}
else
right = mid - 1;
}
cout << ans;
return 0;
}
也许能适用于做某些操作让给定的一组数中的最小值尽可能大的问题。