P1182 数列分段 Section II
题目描述
对于给定的一个长度为N的正整数数列 A_{1\sim N},现要将其分成 M(M\leq N)段,并要求每段连续,且每段和的最大值最小。
关于最大值最小:
例如一数列 要分成 3 段。
将其如下分段:
第一段和为 6,第 段和为 ,第 段和为 ,和最大值为 9。
将其如下分段:
第一段和为 ,第 段和为 ,第 段和为 ,和最大值为 6。
并且无论如何分段,最大值不会小于 。
所以可以得到要将数列 要分成 段,每段和的最大值最小为 。
输入格式
第 1 行包含两个正整数 。
第 2 行包含 N 个空格隔开的非负整数 ,含义如题目所述。
输出格式
一个正整数,即每段和最大值最小为多少。
#include <iostream>
using namespace std;
int n, m; //题目
int a[100007]; // n<=100000
int kl, kr = 1e9 + 1, km; //即l,r,m
int main()
{
cin >> n >> m;
for (int i = 1; i <= n; i++)
{
cin >> a[i], kl = max(kl, a[i]);
}
// l至少为所有元素中最大的值
while (kl < kr) //最上面那个模板
{
km = (kl + kr) / 2; //即>>1
// km代表当前假设的答案,用它去试
int sum = 0, tot = 0; // sum是每段的和,tot是段数
for (int i = 1; i <= n; i++)
{ //枚举每一个数
if (sum + a[i] <= km)
{
sum += a[i];
}
//不用重新分段,就加进去
else
{
sum = a[i], tot++;
}
//分一段,合变为当前数,段数加一
}
if (tot < m)
{
kr = km;
} //段数少,说明数太大,要改小一点(注意是<,因为如果=可能还有更优的答案)
else
{
kl = km + 1;
} //模板
}
cout << kl << endl; //最后kl是答案
return 0;
}

浙公网安备 33010602011771号