一只木桶能盛多少水,并不取决于桶壁上最高的那块木板,而恰恰取决于桶壁上最短的那块。
已知一个木桶的桶壁由N块木板组成,第i块木板的长度为Ai。
现在小Hi有一个快捷修补工具,每次可以使用修补工具将连续的不超过L块木板提高至任意高度。
已知修补工具一共可以使用M次(M*L<N),如何修补才能使最短的那块木板最高呢?
注意: 木板是环形排列的,第N-1块、第N块和第1块也被视为连续的。
Input
第1行:3个正整数,N, M, L。分别表示木板数量,修补工具使用次数,修补工具每次可以同时修补的木板数。 1≤N≤1,000,1≤L≤20,M*L<N
第2行:N个正整数,依次表示每一块木板的高度Ai,1≤Ai≤100,000,000
Output
第1行:1个整数。表示使用修补工具后,最短木块的所能达到的最高高度
Sample Input
8 2 3 8 1 9 2 3 4 7 5
Sample Output
7
Hint
第一个修补工具覆盖[2 3 4]
第二个修补工具覆盖[5 8 1]
思路:可贪心验证+答案单调性,二分答案,验证时枚举起点即可,代码如下:
const int maxm = 100010; const int INF = 0x7fffffff; int buf[maxm], N, M, L; bool check(int d) { int start = 0, sum; while(start < N) { sum = 0; for(int i = start; i < start + N;) { if(buf[i % N] < d) { i += L; sum++; } else i++; } if(sum <= M) return true; start++; } return false; } int main() { scanf("%d%d%d", &N, &M, &L); int l = INF, r = -INF, mid; for(int i = 0; i < N; ++i) { scanf("%d",&buf[i]); l = min(l, buf[i]), r = max(r, buf[i]); } while(l <= r) { mid = (l + r) >> 1; if(check(mid)) l = mid + 1; else r = mid - 1; } printf("%d ", r); return 0; }