序列(二分)

1769: 序列

题目描述

给定一个长度为n的序列,要求将其分成m段序列,每一段连续,并使得每一段和的最大值尽可能小。

输入

第一行两个整数n,m

第二行n个整数,代表序列。

输出

一行一个整数,代表每一段和的最大值的最小值。

样例输入

5 3
4 2 4 5 1

样例输出

6
分析:
我们首先要二分出最大值的最小值
没啥好说的:
scanf("%d%d",&n,&m);
for(int i=1; i<=n; i++) scanf("%d",&a[i]);
int r=2e9,l=0;
while(l+1!=r) {
    int mid=(l+r)/2;
    if(check(mid)/*如果符合*/==1) {
        r=mid;
    } else {
        l=mid;
    }
}    

如何判断最小呢?
先看样例
假设最小值是6
我们先让4当一段的开始
再看2,4+2<=6,所以让4 2形成一段
由于4+6>6
那么后面的4就又是一段的开始,以此类推
所以函数check这样写:
int check(int k) {
    int ans=0,num=0;
    for(int i=1; i<=n; i++) {
        if(a[i]>k) {
            return 0;
        }
        if(a[i]+num<=k) {
            num+=a[i];
        } else {
            num=a[i];
            ans++;
        }
    }
    ans++;
    if(ans<=m) {
        return 1;
    } else {
        return 0;
    }
}

ok

全代码:

#include<bits/stdc++.h>
using namespace std;
int n,m,a[1e6+10]= {0};
int check(int k) {
    int ans=0,num=0;
    for(int i=1; i<=n; i++) {
        if(a[i]>k) {
            return 0;
        }
        if(a[i]+num<=k) {
            num+=a[i];
        } else {
            num=a[i];
            ans++;
        }
    }
    ans++;
    if(ans<=m) {
        return 1;
    } else {
        return 0;
    }
}
int main() {
    scanf("%d%d",&n,&m);
    for(int i=1; i<=n; i++) {
        scanf("%d",&a[i]);
    }
    int r=2e9,l=0;
    while(l+1!=r) {
        int mid=(l+r)/2;
        if(check(mid)==1) {
            r=mid;
        } else {
            l=mid;
        }
    }
    printf("%d",r);
    return 0;
}

 

 
posted @ 2022-05-08 14:48  陈瑞淞  阅读(72)  评论(0)    收藏  举报