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;
}
相关推荐
王璐WL9 小时前
【C语言入门级教学】函数的概念2
c语言·数据结构·算法
不知名的忻10 小时前
B 树与 B+ 树:面试完全指南
b树·算法·面试·b+树
运筹vivo@11 小时前
2657. 找到两个数组的前缀公共数组 | 难度:中等
算法·leetcode·职场和发展·哈希表
索木木11 小时前
NCCL SHARP 和 TREE算法
java·服务器·算法
Lumbrologist11 小时前
【C++】零基础入门 · 第 1 节:第一个程序 Hello World 与编译运行
开发语言·c++
_李小白12 小时前
【C++学习笔记】新特性之inline变量
c++·笔记·学习
心中有国也有家12 小时前
hccl 架构拆解:昇腾集合通信库到底在做什么?
人工智能·经验分享·笔记·分布式·算法·架构
桀人12 小时前
C++——模板初阶(收录在专栏C++入门到精通)
开发语言·c++
小O的算法实验室12 小时前
2026年MCS,Q-learning增强MOPSO与改进DWA融合算法+复杂三维地形下特定移动机器人动态路径规划
算法
Lumbrologist13 小时前
【C++】零基础入门 · 第 2 节:变量、基本数据类型与输入输出
java·开发语言·c++