#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; }