二分最化最值問題(一)
阿新 • • 發佈:2018-04-30
一個人 子序列 兩個 ace ffffff con false std 算法
,意味著我還可以把mid值縮小(最小化),即把二分的right=mid,如果當前mid值觸犯了判斷條件,就把left=mid.
4.由以上二分return
的結果即為所求值.
對於可以計算sum的題有:
二分最化最值問題
把一個包含n個正整數的序列劃分成m個連續的子序列(每個正整數恰好屬於一個序列).
設i個序列的各數之和為s(i).你的任務是讓所有s(i)的最大值盡量小.
這個算法很有現實意義.給你一堆亂七八糟的東西分堆,分出來的東西都不超過一個固定的數值,這是需要技術含量的喔.
1.首先確定二分的上下界,這是每次二分必須做的準備工作.在這裏上限是這一堆東西的總量,下限是單個最大物品的值.
2.確定上下限之後開始二分.即判斷當前分堆是否合理,再判斷分堆是否合理中,主要限制因素為兩個,一個是單堆的量肯定不能超過當前的mid值,另一個是分出的堆數一定不能超過題目要求的m值.
3.由判斷條件即可將二分範圍進行縮小,即一旦當前mid值滿足分堆要求
4.由以上二分return
的結果即為所求值.
#include<bits/stdc++.h> using namespace std; const int N=1e5+5; int a[N]; int ok(int m) { int sum=0,cnt=0; for(int i=0;i<n;i++) { if(a[i] > m) return false; if(sum + a[i] > m) { cnt++; sum = a[i]; } else sum+=a[i]; } return cnt <= m; } int main() { int n,k,sum=0; cin>>n>>k; for(int i=0;i<n;i++) { cin>>a[i]; sum+=a[i]; //r Max=max(Max,a[i); //l } int l=Max,r=sum; while(l<=r) { int mid=(l+r)/2; if(ok(mid)) r=mid; else l=mid+1; } cout<<l<<endl; }
最小化最大值
和最大化最小值問題正好相反,同樣用二分解決,差別主要在判斷條件.
1.最大化最小值(兼濟天下)
相當於把n個東西分給m個人,使得每個人至少拿x個,那麽每個人拿夠了就走,給後面的人多留一點,只要能分夠>=m個人就是true,多的全扔給最後一個人就是了.
2.最小化最大值(獨善其身)
相當於n個東西分給m個人,每個人至多拿x個 ,那麽每個人盡可能拿多一點,給後面的人少留一點,只要能使<=m個人分完n個東西就是true,之後每個人隨便拿一點給沒有拿到的人就是了.
註意:
1.關於初始值,有些題目直接給前綴和,那樣最小值的最大值就是平均值,最大值的最小值也是平均值
2.最大化最小值:
x為單點最小值,y為平均值.
3.最小化最大值:
x為平均值與單點最大值兩者中大的那一個,y為sum.其實直接令x=0,y=0x7fffffff即可,不過循環32次而已...
二分最化最值問題(一)