数列分段-二分法题解

题目描述

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

关于最大值最小:

例如一数列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 个空格隔开的非负整数A_i,含义如题目所述。

输出

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

样例输入

5 3

4 2 4 5 1

样例输出

6

#include <iostream>
using namespace std;

long long int m, n;
long long int num[100010];

bool check(long long int a) {
    int segmentCount = 0, segmentSum = 0;
    for (int i = 0; i < n; i++) {
        if (segmentSum + num[i] <= a) {
            segmentSum += num[i];
        }
        else {
            segmentSum = num[i];
            segmentCount++;
        }
    }
    return segmentCount >= m;
}
int main(void) {
    cin >> n >> m;
    long long int sta=0,end=0;
    for (int i = 0; i < n; i++) {
        cin >> num[i];
        if (sta < num[i]) {
            sta = num[i];
        }
        end += num[i];
    }
    while (sta <= end) {
        long long int mid = (sta + end) / 2;
        if (check(mid)) {
            sta = mid + 1;
        }
        else {
            end = mid - 1;
        }
    }
    cout << sta << endl;
    return 0;
}
import java.util.Scanner;

public class Main {
    static int n,m;
    static int[] num;
    public static void main(String[] args){
        Scanner in=new Scanner(System.in);
        String[] in1=in.nextLine().split(" ");
        n=Integer.parseInt(in1[0]);
        m=Integer.parseInt(in1[1]);
        String[] in2=in.nextLine().split(" ");
        num=new int[n];
        long sta=0, end=0;
        for(int i=0;i<n;i++){
            num[i]=Integer.parseInt(in2[i]);
            if(sta<num[i]){
                sta = num[i];
            }
            end += num[i];
        }
        long mid=(sta+end)/2;
        while(sta<=end){
            if(check(mid)){
                sta = mid + 1;
            }else{
                end = mid - 1;
            }
            mid=(sta+end)/2;
        }
        System.out.println(sta);
    }
    public static boolean check(long a){
        int segmentCount=0,segmentSum=0;
        for(int i=0;i<n;i++){
            if(segmentSum+num[i]<=a){
                segmentSum += num[i];
            }else{
                segmentSum = num[i];
                segmentCount++;
            }
        }
        return segmentCount>=m;
    }
}
def check(a):
    segmentCount, segmentSum = 0, 0
    global m, num
    for i in num:
        if segmentSum + i <= a:
            segmentSum += i
        else:
            segmentSum = i
            segmentCount += 1
    return segmentCount >= m


if __name__ == "__main__":
    in1 = input().split()
    n, m = int(in1[0]), int(in1[1])
    in2 = input().split()
    num = list(map(int, in2))
    sta, end = max(num), sum(num)
    while sta <= end:
        mid = int((sta + end)/2)
        if check(mid):
            sta = mid + 1
        else:
            end = mid - 1
    print(sta)

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值