一个码头中有N艘船和N个木桩,船的长度为2*X,码头的宽度为M,N个木桩的位置(相对码头左岸的位置)会在数据中给出。船和船之间不能重叠,即每艘船的船头不能超过上一艘船的船尾,当然也不能超出码头的两岸。船和木桩之间用绳子连接,并且1个木桩只能栓1条船,绳子的一头拴在木桩上,另一头拴在船的中间。而船中间到木桩的距离,就是所需的绳子的长度。由你根据给出的条件,排列船的位置,使得所用到的最长的绳子最短。输出这个最短的长度,如果码头排不下所有船则输出-1。
例如:N = 3, X = 2, M = 16。三个木桩的位置为:1 3 14。船的长度为2*X = 4。你可以将三艘船放在2 6 14(指的是船中间所处的位置),这样船和船之间既没有重叠,并且所用的最长的绳子最短,长度为3,即第2艘船到第二根木桩的距离。
Input
第1行:3个数N X M,中间用空格分隔(1 <= N <= 50000, 1 <= X <= 10^9, 1 <= M <= 10^9)。 第2 - N + 1行:每行1个数Pi,对应木桩的位置(0 <= Pi <= Pi+1 <= M),并且给出的数据是有序的。
Output
输出最长绳子的最小值。如果码头排不下所有船则输出-1。
Input示例
3 2 16 1 3 14
Output示例
3
题解:很明显可以二分答案,不清楚怎么dp。。。。。据说能O(n)过,不知道怎么操作。
AC代码
#include <stdio.h> #include <iostream> #include <string> #include <queue> #include <map> #include <vector> #include <algorithm> #include <string.h> #include <cmath> typedef long long ll; using namespace std; const ll maxn = 55555; ll loc[maxn]; bool can(ll m, ll n, ll x, ll y){ ll r = 0; //记录当前最右边船的船尾位置 for(ll i = 0; i < n; i++){ if(r + x + m >= loc[i]) r = r + 2 * x; else if(loc[i] - m - x >= r) r = loc[i] - m + x; if(r - x - loc[i] > m) return false; } if(r <= y) return true; else return false; } int main(){ ll n, x, m; scanf("%lld%lld%lld", &n, &x, &m); for(ll i = 0; i < n; i++) scanf("%lld", &loc[i]); if(m < n * 2 * x){ printf("-1\n"); return 0; } ll l = 0, r = m; while(l < r){ ll m1 = (l + r) / 2; if(can(m1, n, x, m)) r = m1; else l = m1 + 1; } printf("%lld\n", l); return 0; }