zoukankan      html  css  js  c++  java
  • YbtOj例题:二分1 数列分段

    http://noip.ybtoj.com.cn/contest/14/problem/1

    虽然这道题是例题,但是它非常的经典。所以我决定写一写。

    通常,求解”最大值最小“或”最小值最大“一类的问题,都会用到二分算法。但仅凭这一个条件无法确定使用二分算法,下面举几个栗子

    1.

    (这是本题)

     总的分组数目有限制,二分有判定条件,可以二分。  答案转化为二分判定

    2.

    洛谷P4047部落划分

     部落总数有限制,可以二分。 答案转化为二分判定

    3.

    洛谷P4447 [AHOI2018初中组]分组

     虽然总的组数没有限制,但我们可以构造出一个单调上升的序列,p[x]表示第x组接下来需要接上的数的大小,它是单调递增的,我们可以二分 二分查找

    4.

    洛谷P1080国王游戏

    这道题就不能二分,因为总钱数没有限制,我们也构造不出一个单调的帮助我们解题的序列。

    回到这道题

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 1e5 + 5, inf = 0x3f3f3f3f;
    int n, m, a[N];
    int l, r = 0;
    bool check(int x) {
        int s = 0, cnt = 1;
        for (int i = 1; i <= n; i++) {
            if (s + a[i] <= x)
                s += a[i];
            else {
                cnt++;
                s = a[i];
            }
        }
    
        return cnt <= m;
    }
    int main() {
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= n; i++) {
            scanf("%d", &a[i]);
            l = max(l, a[i]);
            r += a[i];
        }
        while (l < r) {
            int mid = l + r >> 1;
            if (check(mid))
                r = mid;
            else
                l = mid + 1;
        }
        printf("%d", l);
        return 0;
    }

     还有一个值得我们思考的地方:

    bool check(int x) {
        int s = 0, cnt = 1;
        for (int i = 1; i <= n; i++) {
            if (s + a[i] <= x)
                s += a[i];
            else {
                cnt++;
                s = a[i];
            }
        }
    
        return cnt <= m;
    }

    是return cnt<=m,并用相应的二分形式,还是return cnt>=m并用相应的二分形式呢。

    通过对最优解是奇数还是偶数的讨论,可以得到

    若求最大值,就用小于等于,若求最小值,就用大于等于  maybe

     

    总之, 二分的边界问题非常麻烦,还是要具体问题具体分析。
  • 相关阅读:
    第二次团队作业
    第一次团队作业
    软件工程结对编程第二次作业
    第四次软件工程作业
    Hadoop综合大作业
    hive基本操作与应用
    熟悉HBase基本操作
    爬虫大作业(爬取广州番禺职业技术学院新闻发布方)
    熟悉常用的HDFS操作
    数据结构化与保存
  • 原文地址:https://www.cnblogs.com/smartljy/p/13433799.html
Copyright © 2011-2022 走看看