P1182 数列分段`Section II`

Posted lck-lck

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P1182 数列分段`Section II`相关的知识,希望对你有一定的参考价值。

传送门

思路:

   求数列每段和的最大值的最小值,很明显是用二分法求解,加贪心检验。本题关键是要怎么去高效的check,可以考虑一个贪心的思路,能加的就加上,不能则新开一段,so对于二分的值 u ,我们从数列 sum 从前往后扫,如果 tot 大于了 u ,我们不加而是 tot 重新赋值并且 cnt++ ,最后只需判断 cnt 是否不小于 m 就行了。这样判断与前缀和一样是O(n)的复杂度,但是节省了空间且容易思考。

标程:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<string>
#include<cstdlib>
#include<queue>
#include<vector>
#include<deque>
#include<stack>
#include<map>
#include<set>
using namespace std;
#define maxn 100005
int sum[maxn],tot,n,m,l,r,mid,cnt;
inline int read()
{
    int kr=1,xs=0;
    char ls;
    ls=getchar();
    while(!isdigit(ls))
    {
        if(ls==-)
        kr=-1;
        ls=getchar();
    }
    while(isdigit(ls))
    {
        xs=(xs<<1)+(xs<<3)+(ls^48);
        ls=getchar();
    }
    return kr*xs;
}
inline int lck(int a,int b)
{
    return a>b?a:b;
}
inline int check(int u)
{
    tot=0,cnt=0;
    for(int i=1;i<=n;i++)
    {
        if(tot+sum[i]<=u) tot+=sum[i];
        else tot=sum[i],cnt++;
    }
    return cnt>=m;
}
int main()
{
    n=read();m=read();
    for(int i=1;i<=n;i++)
    {
        sum[i]=read();
        l=lck(sum[i],l);
        r+=sum[i];
    }
    while(l<=r)
    {
        mid=l+r>>1;
        if(check(mid)) l=mid+1;
        else r=mid-1;
    }
    printf("%d
",l);
return 0;
}

注意:二分时的区间取值问题,很明显,对于l的赋值应该取数列中的最大值,而r应该取数列的总和。

以上是关于P1182 数列分段`Section II`的主要内容,如果未能解决你的问题,请参考以下文章

P1182 数列分段`Section II`

P1182 数列分段 Section II

luogu P1182 数列分段Section II

luogu p1182 数列分段Section II

P1182 数列分段`Section II`

洛谷P1182 数列分段Section II 二分答案