这道题很显然是用二分法,大部分人也是这么做的,但是有个问题大家都没注意到,就是二分的初始范围。
二分范围的上限
由于移走了M块岩石,所以还剩下N-M块岩石,将河道分割成了N-M+1个部分,设最短跳跃距离为D,则
D×(N-M+1)<=L
即 D <= L / (N-M+1)
所以最短跳跃距离的最大值= L / (N-M+1)
二分范围的下限
令D1为初始距离的第M+1小值,即初始时一共有M个距离小于D1,由于两个相邻的岩石产生一个距离,对于每个小于D1的距离,任选其两侧的岩石之一取走,这样每取走一个岩石,小于D1的距离就会少一个,取走M个岩石后,岩石之间的最小距离必然 >=D1,可能这句话不好理解,我以一个具体的例子解释一下。
0(7)1(1)2(3)3(4)4(5)5(6)6(2)7(8)8
0、8代表了两端点,1、2、···7代表了7块岩石,括号里的数字代表了岩石之间的距离。假设M=2,则初始距离的第M+1小值为3(2、3岩石之间的距离),比3距离小的距离为1(1、2岩石间)和2(6、7岩石间)。若取走的2个石头是1、2岩石中的一个,6、7岩石中的一个,则距离1和2都不存在了,每取走一个石头,小于D1的距离就少一个,所以最短跳跃距离的最小值必然 >=D1。 即二分初始范围的下限为距离中第M+1小值。
之后的做法就是二分法了,附上AC代码
#include<bits/stdc++.h> #include<math.h> using namespace std; void quickSort(int* a, int l, int r) { if (l < r) { int i, j, x; i = l; j = r; x = a[i]; while (i < j) { while (i < j && a[j] > x) j--; if (i < j) a[i++] = a[j]; while (i < j && a[i] < x) i++; if (i < j) a[j--] = a[i]; } a[i] = x; quickSort(a, l, i - 1); quickSort(a, i + 1, r); } } int main() { int l, m, n, i, a[50000], c[50001], d, e, mid, f = 0, g = 0; cin >> l >> n >> m; d = l / (n - m + 1); for (i = 0;i <= n - 1;i++) { cin >> a[i]; } a[n] = l; c[0] = a[0]; c[n] = l - a[n - 1]; for (i = 1;i <= n - 1;i++) { c[i] = a[i] - a[i - 1]; } quickSort(c, 0, n); e = c[m]; while (e + 1 < d) { g = 0; f = 0; mid = (e + d) / 2; i = 0; while (1) { while (i <= n && a[i] - g < mid) { f++; i++; } if (i >= n) break; if (i < n) { g = a[i]; i++; } } if (f <= m) { e = mid; } else d = mid; } cout << e; return 0; }