51nod-1243 排船的问题

题目来源:  Codility
基准时间限制:1 秒 空间限制:131072 KB 分值: 40  难度:4级算法题
 收藏
 关注
一个码头中有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;
} 

猜你喜欢

转载自blog.csdn.net/qq_37064135/article/details/80010493
今日推荐