给出一个长度为N的正整数数组,不改变数组元素的顺序,将这N个数分为K组。各组中元素的和分别为S1,S2....Sk。如何分组,使得S1至Sk中的最大值最小?
例如:1 2 3 4 5 6分为3组,{1 2 3} {4 5} {6},元素和为6, 9, 6,最大值为9。也可以分为{1 2 3 4} {5} {6}。元素和为:10 5 6,最大值为10。因此第一种方案更优。并且第一种方案的最大值是所有方案中最小的。输出这个最小的最大值。
Input
第1行:2个数N, K,中间用空格分隔,N为数组的长度,K为要分为多少组。(2 <= K < N <= 50000)
第2 - N + 1行:数组元素(1 <= A[i] <= 10^9)
Output
输出这个最小的最大值。
Input示例
6 3
1
2
3
4
5
6
Output示例
9
思路:
先计算出全部元素的和。然后以1为左端点,所有元素和为右端点,进行二分法,尝试以中间值来分组,根据分组数与k比较来确定左右端点的移动。
#include <iostream>
#include <cstdio>
using namespace std;
typedef long long ll;
const int MAXN = 50010;
ll a[MAXN];
ll k, n;
ll total = 0;
int group(ll key)
{
ll sum = 0;
int result = 1;
for (int i = 0; i < n; i++)
{
if (a[i] > key)
{
result = k + 1;
break;
}
else if (sum + a[i] > key)
{
sum = a[i];
result++;
}
else
{
sum += a[i];
}
}
return result;
}
ll search(ll left, ll right)
{
while (left < right - 1)
{
ll mid = left + (right - left) / 2;
if (group(mid) > k)
{
left = mid;
}
else
{
right = mid;
}
}
if (group(left) == k)
{
return left;
}
return right;
}
int main()
{
cin >> n >> k;
for (int i = 0; i < n; i++)
{
cin >> a[i];
total += a[i];
}
cout << search(1, total);
return 0;
}