csp信奥赛C++高频考点专项训练之贪心算法 --【贪心与二分判定】:数列分段 Section II

csp信奥赛C++高频考点专项训练之贪心算法 --【贪心与二分判定】:数列分段 Section II

题目描述

对于给定的一个长度为 N N N 的正整数数列 A 1 ∼ N A_{1\sim N} A1∼N,现要将其分成 M M M( M ≤ N M\leq N M≤N)段,并要求每段连续,且每段和的最大值最小。

关于最大值最小:

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

将其如下分段:

4 2 \] \[ 4 5 \] \[ 1 \] \[4\\ 2\]\[4\\ 5\]\[1\] \[4 2\]\[4 5\]\[1

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

将其如下分段:

4 \] \[ 2 4 \] \[ 5 1 \] \[4\]\[2\\ 4\]\[5\\ 1\] \[4\]\[2 4\]\[5 1

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

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

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

输入格式

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

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

输出格式

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

输入输出样例 #1
输入 #1
复制代码
5 3
4 2 4 5 1
输出 #1
复制代码
6
说明/提示

对于 20 % 20\% 20% 的数据, N ≤ 10 N\leq 10 N≤10。

对于 40 % 40\% 40% 的数据, N ≤ 1000 N\leq 1000 N≤1000。

对于 100 % 100\% 100% 的数据, 1 ≤ N ≤ 10 5 1\leq N\leq 10^5 1≤N≤105, M ≤ N M\leq N M≤N, A i < 10 8 A_i < 10^8 Ai<108, 答案不超过 10 9 10^9 109。

思路分析

本题要求将长度为 N N N 的正整数数列分成连续的 M M M 段,使得各段和的最大值最小 。这是一个典型的"最大值最小化"问题,通常使用二分答案 + 贪心判断解决。

二分答案
  • 假设我们猜测一个值 x,表示当前允许的最大段和。
  • 如果能用不超过 M M M 段实现每段和都 ≤ x,则 x 可行(可能还可以更小)。
  • 否则 `x$ 太小,需要增大。
贪心判断(可行性函数 chk(x)
  • 从左到右遍历数列,维护当前段的和 s
  • 如果 s + a[i] > x,说明 a[i] 不能放入当前段,必须新开一段(段数 c++s = a[i])。
  • 否则 s += a[i]
  • 遍历完成后,若 c ≤ M,则 `x$ 可行。
二分边界
  • 下界 l:数列中的最大值 max(A)(因为每段至少包含一个数,段和不可能小于单个最大值)。
  • 上界 r:题目保证答案不超过 10 9 10^9 109,因此直接取 10 9 10^9 109 作为上界,无需计算总和。
  • 答案在 [l, 1e9] 内,使用二分查找最小的可行值。
复杂度
  • 判断函数 chk 为 O ( N ) O(N) O(N)。
  • 二分次数约为 log ⁡ 2 ( 10 9 ) ≈ 30 \log_2(10^9) \approx 30 log2(109)≈30,总时间复杂度 O ( 30 N ) O(30N) O(30N),空间复杂度 O ( N ) O(N) O(N)。

代码实现

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;

int n,m,a[100010]; //n数列长度,m目标段数,a数列

bool chk(int x){ //判断最大段和x是否可行
    int c=1; //当前段数(至少1段)
    int s=0; //当前段的和
    for(int i=1;i<=n;++i){
        if(s+a[i]>x){ //加上a[i]会超过限制,则新开一段
            ++c; //段数加1
            s=a[i]; //新段从a[i]开始
        }else{
            s+=a[i];  //继续累加
        }
    }
    return c<=m; //段数不超过m则可行
}

int main(){
    scanf("%d%d",&n,&m);
    int l=0,r=1000000000;//l下界(最大值),r上界(题目保证答案≤1e9)
    for(int i=1;i<=n;++i){
        scanf("%d",&a[i]);
        if(a[i]>l) l=a[i]; //更新下界为最大值
    }
    int ans=r;//初始化答案为上界
    while(l<=r){ //二分查找最小可行值
        int mid=l+(r-l)/2;  //中间值,防止溢出
        if(chk(mid)){ //mid可行
            ans=mid; //记录答案
            r=mid-1; //尝试更小值
        }else{
            l=mid+1; //不可行,增大下界
        }
    }
    printf("%d\n",ans);  
    return 0;
}

功能分析

  • 输入处理 :读取 N , M N,M N,M 和数列 A A A,同时计算二分下界 max(A),上界直接设为 10 9 10^9 109(题目保证答案在此范围内)。
  • 二分搜索 :在 [maxA, 1e9] 范围内二分查找,每次取中点 mid 并调用 chk(mid) 判断可行性。当可行时记录 ans=mid 并缩小右边界;不可行时增大左边界。循环条件为 l <= r,确保所有可能值都被检查。
  • 贪心判断chk 模拟分段过程,若当前段和加上下一个数会超过 mid,则必须新开一段;否则继续累加。最后比较实际段数与 M M M。
  • 输出结果 :最终 ans 即为最小的最大段和,输出即可。

各种学习资料,助力大家一站式学习和提升!!!

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
int main(){
	cout<<"##########  一站式掌握信奥赛知识!  ##########";
	cout<<"#############  冲刺信奥赛拿奖!  #############";
	cout<<"######  课程购买后永久学习,不受限制!   ######";
	return 0;
}

【秘籍汇总】(完整csp信奥赛C++学习资料):

1、csp/信奥赛C++,完整信奥赛系列课程(永久学习):

https://edu.csdn.net/lecturer/7901 点击跳转

2、CSP信奥赛C++竞赛拿奖视频课:

https://edu.csdn.net/course/detail/40437 点击跳转

https://edu.csdn.net/course/detail/41081 点击跳转

3、csp信奥赛高频考点知识详解及案例实践:

CSP信奥赛C++动态规划:
https://blog.csdn.net/weixin_66461496/category_13096895.html点击跳转

CSP信奥赛C++标准模板库STL:
https://blog.csdn.net/weixin_66461496/category_13108077.html 点击跳转

信奥赛C++提高组csp-s知识详解及案例实践:
https://blog.csdn.net/weixin_66461496/category_13113932.html 点击跳转

4、csp信奥赛冲刺一等奖有效刷题题解:

信奥赛C++普及组CSP-J一等奖通关刷题题单及题解:
https://blog.csdn.net/weixin_66461496/category_12673810.html 点击跳转

信奥赛C++提高组csp-j初赛&复赛真题题解(持续更新): https://blog.csdn.net/weixin_66461496/category_12808781.html 点击跳转

信奥赛C++提高组csp-s初赛&复赛真题题解(持续更新):
https://blog.csdn.net/weixin_66461496/category_13125089.html 点击跳转

5、GESP C++考级真题题解:

GESP(C++ 一级+二级+三级)真题题解(持续更新):https://blog.csdn.net/weixin_66461496/category_12858102.html 点击跳转

GESP(C++ 四级+五级+六级)真题题解(持续更新):https://blog.csdn.net/weixin_66461496/category_12869848.html 点击跳转

GESP(C++ 七级+八级)真题题解(持续更新):
https://blog.csdn.net/weixin_66461496/category_13117178.html 点击跳转

· 文末祝福 ·

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
int main(){
	cout<<"跟着王老师一起学习信奥赛C++";
	cout<<"    成就更好的自己!       ";
	cout<<"  csp信奥赛一等奖属于你!   ";
	return 0;
}
相关推荐
zh_xuan1 小时前
libcurl调用https接口
c++·libcurl
就叫飞六吧1 小时前
QT写一个桌面程序exe并动态打包基本流程(c++)
开发语言·c++
蜡笔小马1 小时前
1.c++设计模式-工厂模式
c++
V搜xhliang02462 小时前
OpenClaw科研全场景用法:从文献到实验室的完整自动化方案
运维·开发语言·人工智能·python·算法·microsoft·自动化
汉克老师2 小时前
GESP2025年3月认证C++五级( 第三部分编程题(2、原根判断))
c++·算法·模运算·gesp5级·gesp五级·原根·分解质因数
winner88812 小时前
从零吃透C++命名空间、std、#include、string、vector
java·开发语言·c++
数据皮皮侠2 小时前
上市公司创新韧性数据(2000-2024)|顶刊同款 EIR 指数
大数据·人工智能·算法·智慧城市·制造
WL_Aurora2 小时前
Python 算法基础篇之链表
python·算法·链表
科研前沿2 小时前
纯视觉无感解算 + 动态数字孪生:室内外无感定位技术全新升级
大数据·人工智能·算法·重构·空间计算