数列分段 II(二分)

题目描述

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

例如,将数列 4  2  4   5  1 要分成 3 段:

若分为 [4 2][4 5][1],各段的和分别为 6, 9, 1 ,和的最大值为 9;

若分为 [4][2 4][5 1],各段的和分别为 4, 6, 6 ,和的最大值为 6;

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

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

输入格式

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

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

输出格式

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

样例

输入

5 3
4 2 4 5 1

输出

6

数据范围与提示

对于 20%的数据,有 N <=10;

对于 40% 的数据,有 N <=1000;

对于 100%的数据,有 N <= 10^5,M <= N, Ai 之和不超过 10^9 。

本题需要的主要思路是先找出最大值和最小值,让后二分查找,二分查到的数判断是否符合题意,

让后不断二分,直到查找到答案为止;

#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <vector>
#include <map>
#include <math.h>
using namespace std;
#define endl "\n"
#define debug(var) \
        cout<<#var<<"======="<<var<<endl
#define int long long
int s, e, i, n, m, a[100010], r, mid, w;
bool find(int w) {
    s = 0, e = 1;

    for (i = 1; i <= n; i++) {
        if (s + a[i] > w) {
            s = a[i];
            e++;
        } else
            s += a[i];
    }

    if (e <= m)
        return 1;
    else
        return 0;
}
void ycc() {
    cin >> n >> m;
    {
        int l = 1;
        r = 1e9;

        for (i = 1; i <= n; i++) {
            cin >> a[i];
            l = max(l, a[i]);
        }

        while (l < r) {
            mid = (l + r) / 2;

            if (find(mid))
                r = mid;
            else
                l = mid + 1;
        }

        cout << r << endl;
    }
}
signed main() {
    ios::sync_with_stdio(false);
    cin.tie(0);//cout<<" 1 "<<endl;
    ycc();
    return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值