洛谷题解:P2678 [NOIP2015 提高组] 跳石头
题目:
这项比赛将在一条笔直的河道中进行,河道中分布着一些巨大岩石。组委会已经选择好了两块岩石作为比赛起点和终点。在起点和终点之间,有 N 块岩石(不含起点和终点的岩石)。在比赛过程中,选手们将从起点出发,每一步跳向相邻的岩石,直至到达终点。
为了提高比赛难度,组委会计划移走一些岩石,使得选手们在比赛过程中的最短跳跃距离尽可能长。由于预算限制,组委会至多从起点和终点之间移走 M 块岩石(不能移走起点和终点的岩石)。
输入格式:
第一行包含三个整数 n,m,分别表示矿石的个数、区间的个数和标准值。
接下来的 n 行,每行两个整数,中间用空格隔开,第 i+1 行表示 i 号矿石的重量 wi 和价值 vi。
接下来的 m 行,表示区间,每行两个整数,中间用空格隔开,第 i+n+1行表示区间 [li,ri] 的两个端点 li 和 ri。注意:不同区间可能重合或相互重叠。
输出格式:
第一行包含三个整数 L,N,M,分别表示起点到终点的距离,起点和终点之间的岩石数,以及组委会至多移走的岩石数。保证 L≥1 且 N≥M≥0。
接下来 N 行,每行一个整数,第 i 行的整数 Di(0<Di<L), 表示第 i 块岩石与起点的距离。这些岩石按与起点距离从小到大的顺序给出,且不会有两个岩石出现在同一个位置。
样例:
输入:
25 5 2
2
11
14
17
21
输出:
4
分析:
这道题一般思路就是对于每一个可能的最小距离进行判断,在允许的范围内找到最大的最小距离。
直接执行的化应该是会TLE,这时候可以考虑二分,因为存在一个单调的关系,最小距离越大,需要去掉的石头越多,所以我们以最小距离为区间,找到最合适的去掉石头的个数。
这里道理想明白了其实就清楚了。
代码:
#include<iostream>
#include<string>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
using namespace std;
long long L,N,M;
long long D[100005] = {0};
bool check(long x)
{
long long sum = 0;
long long s = 0;
for(long long i = 1;i <= N + 1;i++)
{
if(D[i] - s < x)
{
sum++;
}
else
{
s = D[i];
}
}
return sum <= M;
}
int main()
{
cin>>L>>N>>M;
for(int i = 1;i <= N;i++)
{
cin>>D[i];
}
long long left = 1;
long long right = L;
D[N + 1] = L;
while(left + 1 < right)
{
long long mid = (left + 1 + right) >> 1;
if (check(mid))
{
left = mid;
}
else
{
right = mid;
}
}
if(check(right))
{
left = right;
}
cout<<left<<endl;
return 0;
}