洛谷 P1182 数列分段 Section II

该博客详细介绍了如何解决洛谷P1182数列分段问题,主要利用二分查找算法。通过分析题目要求,确定数组并进行排序,设置left和right边界,不断更新middle值并与数组元素比较。当分组数量m改变时,答案可能在最大值或数组和之间。博主分享了如何构建比较条件以及如何在二分查找中处理边界情况,最终实现O(nlogn)时间复杂度的解题方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原题链接:洛谷 P1182 数列分段 Section II

题目要求

题目大意为:输入一个n列数组,分成m段,对数组输出一个正整数,即每段和最大值最小为多少。
例如:
5 3
4 2 4 5 1
最小为【4】、【2 4】、【5 1】,分组中,最小的最大组值为6。

解题思路

本题用到二分查找的算法。
二分的具体用法如下:
先确定一个数组:有的是题目直接给的,有的需要自己推测题意寻找数组。前者比较简单,直接排好序,确定好left=0;right=n-1。**再让middle=(left+right)/2,与要查找的数据find作比较。如果middle<=find,让left=middle+1,否则right=middle-1。**前面一句进行循环,直至left>=right为止,说明答案找到。
二分算法的时间复杂度为:O()=O(logn)。
但是这一题的难度在于,怎么找到要进行二分查找的数组?我们可以往极限的方向去想,如例子:
5 3
4 2 4 5 1 //如果分组3改为1,那么,答案一定是数组中最大的“5”,如果分组改为5,那么答案为数组数据之和。
所以,要进行查找的数组为:left=max(a[n]),right=sum(a[n]),middle=(left+right)/2,问题又出来了,中间值出来了,与谁作比较呢?因为要把数组分组,所以可以遍历a数组,将遍历的sum(a[i])与middle作比较,如果大了,继续加;如果小了就记录一下(num++),最后,看看小了的那些组之和(num)是不是比m小,如果小的话,说明答案藏在左半部分,否则,答案藏在右半部分。
在用二分查找的时候,切记切记,一定要把边界找好喽!

正确代码

#include <iostream>
#include<bits/stdc++.h>

using namespace std;


int main()
{

    int rin=0,len=0; //二分的左右边界,一定要清零!!!
    int n,m;

    cin>>n>>m;
    int a[n];
    for(int i=0;i<n;i++){ //O(n)时空复杂度
        cin>>a[i];
        rin+=a[i];  //这里二分的右边界为数组所有数字之和
        len=len>a[i]?len:a[i];//这里二分的左边界为数组中最大的数字。
    }
    while(len<=rin){  //当还没找到时,O(nlogn)时间复杂度
        int sum=0,num=0;
        int mi=(len+rin)/2; //二分
        for(int i=0;i<n;i++){ //遍历当前的mi值是大了还是小了。
            if(sum+a[i]<=mi)
                sum+=a[i];
            else{
                sum=a[i];
                ++num;
            }
        }
        if(num>=m) len=mi+1; //答案在后半部分
        else rin=mi-1; //答案在左半部分
    }
    cout<<len;
    return 0;
}

本题时间复杂度:O(nlogn)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值