P1182 数列分段 Section II

题目描述

对于给定的一个长度为N的正整数数列 A_{1\sim N},现要将其分成 MM\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;
}

 

posted @ 2022-01-14 15:47  亚托莉的亚托莉  阅读(56)  评论(0)    收藏  举报