51nod 1243 二分+贪心

http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1243

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,但一眼看去就是二分呀,,于是愉快的错了一晚上,最后删了重写几遍才过。
    对于一个最长长度x,判断他是否能满足要求,用pos记录上一个船的尾部位置,如果x[i]<=pos+X,显然接着上一个船放置最优,如果不合法显然往后放置更不会合法。
否则的话,将船尽可能的往左边放置,能正好在xi左边-k处就这样放,如果不足k的话接着上一个放置即可。
 
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define LL long long
 4 LL mod=1e9+7;
 5 int x[50005],N,X,M;
 6 bool ok(int k)
 7 {
 8     int pos=0,len=X*2;
 9     for(int i=1;i<=N;++i)
10     {
11         if(x[i]<=pos+X){
12             if(pos+X-x[i]<=k) pos+=len;
13             else return 0;
14         }
15         else{
16             if(x[i]-(pos+X)<=k) pos+=len;
17             else pos=x[i]-k+X;
18         }
19     }
20     return pos<=M;
21 }
22 int main()
23 {
24     int i,j,k;
25     scanf("%d%d%d",&N,&X,&M);
26     for(i=1;i<=N;++i)
27     {
28         scanf("%d",x+i);
29     }
30     int l=0,r=M;
31    while(l<r)
32     {
33         int mid=l+(r-l)/2;
34         if(ok(mid)) r=mid;
35         else l=mid+1;
36     }
37 
38     if(ok(l)) cout<<l<<endl;
39     else puts("-1");
40     return 0;
41 }
原文地址:https://www.cnblogs.com/zzqc/p/7468032.html