zoukankan      html  css  js  c++  java
  • 5.9每日一题题解

    数列分段 Section II

    涉及知识点:

    • 二分/思维

    solution

    • (我们可以看到它让求的是最大值最小问题,诸如最大值最小,最小值最大这种问题,我们都可以使用二分答案来求解。)
    • (即然要使用二分,我们就需要解决两个问题:)
    • (1. 二分的左右边界是什么?)
    • (左边界表示答案的最小取值,很显然,它最小的情况下只能是所给数的最大值,所以左边界取数列的最大值)
    • (右边界表示答案的最大取值,由于本题说明给出的数都为正整数,所以只要把所有数相加就是右边界)
    • (2. 二分的判断条件是什么?)
    • (我们可以假设当前的mid为我们的答案,然后按照条件判断。)
    • (从头按照将mid看成最大值来分区域,如果划分的区域数小于等于规定的区域数则为真,否则为假。)

    代码

    #include <iostream>
    #include <cstdio>
    
    using namespace std;
    
    const int N = 1e5+10;
    
    int n,m;
    int a[N];
    int l=-1,r=0;
    
    bool check(int x)
    {
        int i = 0;//表示当前遍历到第几个数
        int section = 1;//以x为最大值划分的区域个数,初始为1
        int sum = 0;//表示当前区域的和
        while (i <= n-1)//由于循环里无论结果怎样i都会加一,所以只要循环到n-1就可以完成1~n的循环
        {
            if(sum + a[i+1] <= x) sum += a[++i];//如果下一个数加上sum还没到x,则继续遍历
            else sum = a[++i],section++;//如果下一个数加上sum比x要大,则下一个数就是一个新的区域
        }
        if(section <= m) return true;//如果划分的区域数比m小,返回true
        else return false;//如果划分的区域数比m大,返回false
    }
    
    int main()
    {
        scanf("%d%d",&n,&m);
        for (int i = 1 ; i <= n ; i ++ )
        {
            scanf("%d",&a[i]);
            l = max(l,a[i]);//左边界取数列的最大值
            r = r + a[i];//右边界为数列的和
        }
        
        while (l < r)
        {
            int mid = l + r >> 1;
            if(check(mid)) r = mid;//如果划分的数量比m小,说明mid过大,则答案在mid左边或等于mid
            else l = mid+1;//如果划分的数量比m大,说明mid过小,则答案在mid右边
        }
        printf("%d
    ",l);
        return 0;
    }
    
  • 相关阅读:
    配置sql server 2000以允许远程访问
    SQLServer大数据量插入BULK INSERT
    【项目经理之修炼(5)】《基础篇》别把项目成功当目标(转)
    C#XML文件操作类
    winform窗体总在所有窗体最上层
    配置VSS2005的Internet访问(转)
    U盘引导盘制作
    【项目经理之修炼(4)】《基础篇》故事的主角是你吗?(转)
    SQLServer收缩数据库日志
    【项目经理之修炼(1)】《序章》关于要写给谁看的问题(转)
  • 原文地址:https://www.cnblogs.com/QFNU-ACM/p/12854607.html
Copyright © 2011-2022 走看看