二分入門練習題6 最大值最小化 題解

2022-08-19 22:15:10 字數 1625 閱讀 4636

題目描述

在印刷術發明之前,複製一本書是乙個很困難的工作,工作量很大,而且需要大家的積極配合來抄寫一本書,團隊合作能力很重要。當時都是通過招募抄寫員來進行書本的錄入和複製工作的, 假設現在要抄寫 \(m\) 本書,編號為 \(1,2,3...m\) , 每本書有 \(1 \le x \le 100000\) 頁, 把這些書分配給 \(k\) 個抄寫員,要求分配給某個抄寫員的那些書的編號必須是連續的,每本書只能被乙個抄寫員抄寫。每個抄寫員的速度是相同的,你的任務就是找到乙個最佳的分配方案,使得所有書能夠被抄完的前提下,每個抄寫員所抄寫的頁數最少。

輸入格式

在第一行中,有兩個整數 \(m 和 k, 1<=k,m<=100000\) 。 在第二行中,有 \(m\) 個整數 \(x_i\) 用空格分隔。 所有這些值都為正且小於 \(100000\) 。

輸出格式

輸出一行數字,代表最佳的分配方案中,全部抄寫完畢,抄寫頁數最多的抄寫員所抄寫的頁數。

樣例輸入

9 3

100 200 300 400 500 600 700 800 900

樣例輸出
1700
題目分析

這道題目是二分答案。

首先我們可以編寫乙個bool check(int num)函式來判斷在分配給每個抄寫員 \(num\) 頁書時 \(k\) 個抄寫員是否能夠超寫完 \(m\) 本書。如果可以,\(check(num)\) 返回true;否則,\(check(num)\) 返回false

然後,我們會發現:

那麼在 \(0\) 和 \(\sum_^nx_i\) 之間肯定存在乙個最小的 \(num\) 使得 \(check(num)\) 返回true

我們可以發現:

所以如果我們以答案num為自變數,以答案是否成立(\(check(num)\) 返回的結果)為應變數,我們可以得到乙個應變數隨自變數變化的單調函式曲線。

實現**如下:

#include using namespace std;

const int maxn = 100010;

int m, k; // m表示書有多少本,k表示抄寫員的數量

long long a[maxn]; // a[i]表示第i本書的頁數

// check函式用於判斷分配給沒個抄寫員num頁書的時候能否超寫完

bool check(long long num)

else if (a[i] > num) // 如果a[i]>num,說明任何抄寫員都抄寫不了第i本書

return false;

else

}return true; // 返回true

}int main()

long long l = 0, r = sum, res; // l記錄答案的左邊界,r記錄答案的右邊界,res記錄答案

while (l <= r)

else l = mid + 1; // 進有半部分找解

}cout << res << endl; // 輸出答案

return 0;

}

二分 最小化最大值

注意答案的二分性質,必須要滿足在滿足給定條件的所有情況的時候都滿足要求才能更新ans。include using namespace std typedef long long ll inline ll in while c 0 c 9 res res 10 c 48,c getchar retur...

zzuli 1919 二分 最大值最小化

description 晴天想把乙個包含n個整數的序列a分成連續的若干段,且和最大的一段的值最小,但他有強迫症,分的段數不能超過m段,然後他就不會分了。他想問你這個分出來的和最大的一段的和最小值是多少?input 第一行輸入乙個整數t,代表有t組測試資料。每組資料第一行為兩個整數n,m分別代表序列的...

POJ 3273(二分,最小化最大值)

和這道題一樣了 description 聰哥在暑假參加了打零工的活動,這個活動分為n個工作日,每個工作日的工資為vi。有m個結算工錢的時間,聰哥可以自由安排這些時間,也就是說什麼時候拿錢,老闆說的不算,聰哥才有發言權!因為聰哥是土豪,他是老闆的老闆 聰哥不喜歡身上一次性有太多的錢,於是他想安排一下拿...