题目传送门
一、为什么可以使用二分,怎么想到的?
每段和的最大值最小。
,提示的很明显,什么最大值最小,最小值最大等等,均可以视为二分答案题。为啥呢?因为二分的本质是区间逼近,这样才能求出极值,不用二分你说用啥?
二、二分查找的是什么?
本题查找的肯定是
每段和的最大值
,逼近的是让它最小。
三、左右边界值是多少?
每段和的极限情况:(1)一个数字一段;(2)所有数字在一段里。
每个数字独自一段的话,最大值就是\(max(a[i])\)
所有数字在一段的话,最大值就是\(sum(a[i])\)
四、是向左逼近,还是向右逼近?
求最大值的最小。即向左逼近
五、check函数的实现
按东北话来讲,就是:逮着一个往死了加,直到冒了就再开一个房间~
最终是否符合是题意要求就是: \(cnt<=m\)
六、C++代码
#include <bits/stdc++.h>
using namespace std;
const int N = 100010;
int a[N];
int n, m;
//检查函数
bool check(int mid) {
int cnt = 1; //最小一个区间
int sum = 0; //区间和
for (int i = 1; i <= n; i++) {
//区间和计算
sum += a[i];
//如果超过了mid值
if (sum > mid) {
cnt++; //需要下一个段了~
sum = a[i];
}
}
//是否符合题意的要求,在m个区间段范围内?
return cnt <= m;
}
int l, r;
int main() {
cin >> n >> m;
//输入
for (int i = 1; i <= n; i++) {
cin >> a[i];
l = max(l, a[i]);
r += a[i];
}
while (l < r) {
int mid = l + r >> 1;//mid的定义:每段和
if (check(mid)) r = mid;//向左逼近
else l = mid + 1;
}
//输出大吉
cout << l << endl;
return 0;
}