题目描述
对于给定的一个长度为 N 的正整数数列 A ,现要将其分成 M 段,并要求每段连续,且每段和的最大值最小。
例如,将数列 4 2 4 5 1 要分成 3 段:
若分为 [4 2][4 5][1],各段的和分别为 6, 9, 1 ,和的最大值为 9;
若分为 [4][2 4][5 1],各段的和分别为 4, 6, 6 ,和的最大值为 6;
并且无论如何分段,最大值不会小于 6。
所以可以得到要将数列 4 2 4 5 1 要分成 3 段,每段和的最大值最小为 6 。
输入格式
第 1 行包含两个正整数 N,M;
第 2 行包含 N 个空格隔开的非负整数 A_i,含义如题目所述。
输出格式
仅包含一个正整数,即每段和最大值最小为多少。
样例
输入
5 3
4 2 4 5 1
输出
6
数据范围与提示
对于 20%的数据,有 N <=10;
对于 40% 的数据,有 N <=1000;
对于 100%的数据,有 N <= 10^5,M <= N, Ai 之和不超过 10^9 。
本题需要的主要思路是先找出最大值和最小值,让后二分查找,二分查到的数判断是否符合题意,
让后不断二分,直到查找到答案为止;
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <vector>
#include <map>
#include <math.h>
using namespace std;
#define endl "\n"
#define debug(var) \
cout<<#var<<"======="<<var<<endl
#define int long long
int s, e, i, n, m, a[100010], r, mid, w;
bool find(int w) {
s = 0, e = 1;
for (i = 1; i <= n; i++) {
if (s + a[i] > w) {
s = a[i];
e++;
} else
s += a[i];
}
if (e <= m)
return 1;
else
return 0;
}
void ycc() {
cin >> n >> m;
{
int l = 1;
r = 1e9;
for (i = 1; i <= n; i++) {
cin >> a[i];
l = max(l, a[i]);
}
while (l < r) {
mid = (l + r) / 2;
if (find(mid))
r = mid;
else
l = mid + 1;
}
cout << r << endl;
}
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(0);//cout<<" 1 "<<endl;
ycc();
return 0;
}