帮我用c++写一段给一个序列a1,a2,…,an。 你想把这个序列划分成k段,对于每一段求和,希望这k段的和里面最小值最大。问这个值是多少。
时间: 2024-05-01 10:23:16 浏览: 90
MAX SUM {a1,a2,…,an},求该序列形如ai+ai+1,…,+aj的子段和的最大值
5星 · 资源好评率100%
好的,这是一个经典的二分答案问题,可以使用贪心算法和二分答案相结合来解决。
以下是 C++ 代码实现:
```c++
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1e5 + 5;
int n, k;
int a[N];
bool check(int x) {
int cnt = 0, sum = 0;
for (int i = 1; i <= n; i++) {
if (a[i] > x) return false;
sum += a[i];
if (sum > x) {
cnt++;
sum = a[i];
}
}
cnt++;
return cnt <= k;
}
int main() {
cin >> n >> k;
int l = 0, r = 0;
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) / 2;
if (check(mid)) r = mid;
else l = mid + 1;
}
cout << l << endl;
return 0;
}
```
首先读入序列,然后初始化二分的左边界为序列中的最大值,右边界为序列的总和。进入二分循环,在每一次循环中,先求出当前的中间值 mid,然后使用 check 函数来检测是否能够将序列划分成 k 段,使得每一段的和都不超过 mid。如果能够划分成 k 段,则说明 mid 可以更小,因此将右边界更新为 mid。如果不能划分成 k 段,则说明 mid 需要更大,因此将左边界更新为 mid+1。最终的答案就是二分结束时的左边界值。
check 函数的实现为,遍历序列中的每一个数,如果当前数大于 mid,则无法划分成 k 段,直接返回 false。否则,将当前数加入当前段的和 sum 中,如果 sum 大于 mid,则说明当前段已经不能再加入数了,因此将当前段数 cnt 加 1,并将 sum 重置为当前数。最后,为了保证序列被划分成 k 段,还需要将 cnt 加 1。如果 cnt 小于等于 k,则说明 mid 可以更小,返回 true;否则 mid 需要更大,返回 false。
阅读全文