修补木桶

题目1 : 修补木桶

时间限制:10000ms

单点时限:1000ms

内存限制:256MB

描述

一只木桶能盛多少水,并不取决于桶壁上最高的那块木板,而恰恰取决于桶壁上最短的那块。

已知一个木桶的桶壁由N块木板组成,第i块木板的长度为Ai。

现在小Hi有一个快捷修补工具,每次可以使用修补工具将连续的不超过L块木板提高至任意高度。

已知修补工具一共可以使用M次(M*L<N),如何修补才能使最短的那块木板最高呢?

注意: 木板是环形排列的,第N-1块、第N块和第1块也被视为连续的。

输入

第1行:3个正整数,N, M, L。分别表示木板数量,修补工具使用次数,修补工具每次可以同时修补的木板数。 1≤N≤1,000,1≤L≤20,M*L<N

第2行:N个正整数,依次表示每一块木板的高度Ai,1≤Ai≤100,000,000

输出

第1行:1个整数。表示使用修补工具后,最短木块的所能达到的最高高度

样例说明

第一个修补工具覆盖[2 3 4]

第二个修补工具覆盖[5 8 1]

 

样例输入

8 2 3
8 1 9 2 3 4 7 5

样例输出

7

 

假设最终最短的木板长度至少是K,最小需要使用修复工具几次? 为了描述方便我们将这个最少次数记作F(K)。

于是我们的问题变成求出最大的K,满足F(K) <= M。

如果我们将F(K)看成一个函数,随着K增加,我们要修复的木板越来越多,显然F(K)也会越来越大。

换句话说F(K)是单调递增的。我们可以用二分来求出最大的K。

 

import java.util.Arrays;
import java.util.Scanner;

public class Main {
    public static void main(String[] argv){
        Scanner in = new Scanner(System.in);
        int N=in.nextInt(),M=in.nextInt(),L=in.nextInt();
        int[] height=new int[N];
        for(int i=0;i<N;++i)
            height[i]=in.nextInt();
        int[] sorted=Arrays.copyOf(height,height.length);
        Arrays.sort(sorted);
        int l=0,r=N-1;
        int h=0;
        while(l<=r){
            int m=(l+r)/2;
            h=sorted[m];
            if(fix(height,h,L)>M)  r=m-1;
            else    l=m+1;
        }
        System.out.println(sorted[r]);
    }

    static int fix(int[] height, int h, int L){
        int N=height.length;
        int p;
        for(p=0;p<N;++p)
            if(height[p]<h) break;
        if(p==N)    return 0;
        int min=10000;
        for(int i=-L+1;i<=0;++i){
            int s=(p+N+i)%N;
            int num=0;
            for(int j=0;j<N;++j){
                int k=(j+s)%N;
                if(height[k]<h){
                    num++;
                    j+=(L-1);
                }
            }
            min=Math.min(num,min);
        }
        return min;
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值