• 【洛谷 P1182】数列分段 Section II 题解(二分答案+循环)


    数列分段 Section II

    题目描述

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

    关于最大值最小:

    例如一数列 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
    • 2

    样例输出 #1

    6
    
    • 1

    提示

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

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

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


    思路

    函数check用来判断当前的x是否满足条件。在函数check中,会遍历数列a[N],将当前位置的数加到sum上,并判断sum是否超过x。如果超过x,则创建新区间,将sum重新赋值为当前位置的数,并将cnt加1。最后,返回cnt是否大于m。

    首先读入n和m的值,然后读入数列a[N]的值,并初始化l和r的值。因为所有元素都要划入区间内,所以要保证最大的元素也要被划进某一个区间,l初始化为数列a[N]中的最大值。如果把所有元素都划进区间,那么区间的最大值肯定不会超过所有元素的和,r初始化为数列a[N]中所有数的和。

    使用二分法来寻找满足条件的x。在每一次循环中,计算mid的值,并调用check函数判断是否满足条件。如果满足条件,则说明x偏小,将l更新为mid+1。如果不满足条件,则说明x偏大,将r更新为mid-1。

    注意:check函数中,需要将区间数cnt初始化为1,因为最少有一个区间。


    AC代码

    #include 
    #include 
    #define AUTHOR "HEX9CF"
    using namespace std;
    
    const int N = 1e6 + 7;
    
    int n, m;
    int a[N];
    
    bool check(int x) {
    	int sum = 0;
    	int cnt = 0;
    	for (int i = 1; i <= n; i++) {
    		int tmp = sum + a[i];
    		if (tmp > x) {
    			sum = a[i];
    			cnt++;
    		} else {
    			sum = tmp;
    		}
    	}
    	// cout << x << " " << cnt << endl;
    	return cnt >= m;
    }
    
    int main() {
    	int l, r, mid;
    	l = 0;
    	r = 0;
    	cin >> n >> m;
    	for (int i = 1; i <= n; i++) {
    		cin >> a[i];
    		l = max(l, a[i]);
    		r += a[i];
    	}
    	while (l <= r) {
    		mid = (l + r) >> 1;
    		if (check(mid)) {
    			// 偏小
    			l = mid + 1;
    		} else {
    			// 偏大
    			r = mid - 1;
    		}
    	}
    	cout << l << endl;
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
  • 相关阅读:
    FreeRTOS操作系统中,断言输出 Error:..\..\FreeRTOS\portable\RVDS\ARM_CM4F\port.c,766 原因
    QT实现TCP通信(服务器与客户端搭建)
    OCR技术狂潮:揭秘最新发展现状,引爆未来智能时代
    day16_购物车(添加购物车,购物车列表查询,删除购物车商品,更新选中商品状态,完成购物车商品的全选,清空购物车)
    【快速掌握Docker】Docker高级运用汇总--Dockerfile、Docker Compose与Docker Swarm使用
    Kerberos认证系统
    300道SpringCloud面试题2022(面试题及答案)
    WebDAV之葫芦儿·派盘本地个人云+Documents
    WPF页面向后端传参
    获得淘宝商品详情 API 返回值说明
  • 原文地址:https://blog.csdn.net/qq_34988204/article/details/134491521