洛谷刷题C++语言 | P1182 数列分段

学习C++从娃娃抓起!记录下洛谷C++学习和备考过程中的题目,记录每一个瞬间。

附上汇总贴:洛谷刷题C++语言 | 汇总_热爱编程的通信人的博客-CSDN博客


【题目描述】

对于给定的一个长度为N的正整数数列 A1~N,现要将其分成 MMN)段,并要求每段连续,且每段和的最大值最小。

关于最大值最小:

例如一数列 4 2 4 5 1 要分成 3 段。

将其如下分段:

[4 2][4 5][1]

第一段和为 6,第 2 段和为 9,第 3 段和为 1,和最大值为 9。

将其如下分段:

[4][2 4][5 1]

第一段和为 4,第 2 段和为 6,第 3 段和为 6,和最大值为 6。

并且无论如何分段,最大值不会小于 6。

所以可以得到要将数列 4 2 4 5 1 要分成 3 段,每段和的最大值最小为 6。

【输入】

第 1 行包含两个正整数 N,M

第 2 行包含 N 个空格隔开的非负整数 Ai,含义如题目所述。

【输出】

一个正整数,即每段和最大值最小为多少。

【输入样例】

5 3
4 2 4 5 1

【输出样例】

6

【代码详解】

#include <bits/stdc++.h>
using namespace std;
int n, m, a[100005], l=0, r=0;
int main()
{
    cin >> n >> m;
    for (int i=1; i<=n; i++) {
        cin >> a[i];
        if (l<a[i]) l = a[i];
        r += a[i];
    }
    // cout << "l r " << l << " " << r << endl;
    while (l<=r) {
        int mid = l + (r-l)/2;
        // cout << "mid " << mid << endl;
        int count = 1, tmp=0;  // 初始分段至少1段
        for (int i=1; i<=n; i++) {
            if (a[i]+tmp<=mid) tmp += a[i];  // 至少是1段,所以要加上a[i]
            else {
                count++;
                tmp = a[i];
            }
        }
        if (count<=m) r= mid-1;
        else l = mid+1;
    }
    cout << l << endl;
    return 0;
}

【运行结果】

5 3
4 2 4 5 1
6