HihoCoder 1362-修补木桶(二分)

#1362 : 修补木桶

时间限制: 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

解题思路:这道题的难点主要是找二分条件:我们对最大高度进行二分,然后再去枚举在限定的修补次数内是否可以完成该高度的修补。
AC代码:
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#include<queue>
#include<map>
#define bug printf("--------");
using namespace std;
typedef long long LL;
const int INF = 1e9;
const int mod = 1e9+7;

int n, m, l, a[1010], b[1010];

bool check(int h)
{
    for(int k = 0; k < n; k ++) { //枚举修补的起点
        for(int i = 0; i < n; i ++)
            b[i] = a[i];
        int sum = 0, s = 0;
        for(int i = k; i < n; i ++) {
            if(b[i] < h) { //低于h就需要修补了
                for(int j = i; j < i+l; j ++) {
                    b[j%n] = 1e8;
                }
                sum ++;
            }
            if(sum >= m) break;
        }
        sort(b, b+n);
        if(b[0] >= h) return true; //最低高度
    }
    return false;
}

int main()
{
    while(~scanf("%d%d%d", &n, &m, &l)) {
        for(int i = 0; i < n; i ++)
            scanf("%d", &a[i]);
        int l = 0, r = 1e9;
        while(l+1 < r) {
            int mid = (l+r)/2;
            if(check(mid)) l = mid;
            else r = mid;
        }
        if(check(l+1)) printf("%d\n", l+1);
        else printf("%d\n", l);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/I_believe_CWJ/article/details/80270233
今日推荐