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;
    }
    
  • 相关阅读:
    一个星期自动态的网站设计
    java特权制度设计篇
    mac默认截图、截图代码
    NSDateFormatter
    vlan 以及 Linux实现的IEEE 802.1Q VLAN
    gtk+blade+anjuta 的简单实例
    NetBSD是个开源到源码的系统
    创作gtk源码级vim帮助文档 tags
    linux 怎么使用一个c/c++库
    linux 终端控制-- 多彩输出 格式排版
  • 原文地址:https://www.cnblogs.com/QFNU-ACM/p/12854607.html
Copyright © 2011-2022 走看看