zoukankan      html  css  js  c++  java
  • 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应该取数列的总和。

  • 相关阅读:
    git打补丁、还原补丁
    mysql 查两个表相同的值
    系统更新后vs2012无法打开方案资源管理器
    Node.js之Buffer
    html元素固定
    在windows上用netsh动态配置端口转发
    Git忽略规则及.gitignore规则不生效的解决办法
    MySQL5.7.10 初始化失败error
    Nginx和PHP-FPM的启动、重启、停止脚本分享
    centos添加nginx为系统服务
  • 原文地址:https://www.cnblogs.com/lck-lck/p/9692008.html
Copyright © 2011-2022 走看看