Living-Dream 系列笔记 第4期
本期主要讲解二分答案。
知识点
使用场景:
-
最小值最大化,或最大值最小化。
-
在限制条件下找最值。
与二分查找的区别:
L
、R
均为答案,而非下标。
输出:
- 最大化输出
L
,反之输出R
。
例题
T1
二分 \(M\) 的值,边界为 \(L=-1,R=\max{\{a_i\}}\)。每次枚举到一个 \(mid\) 就对于每个 \(a_i\),计算能砍下的木头是否 \(\ge m\)。
#include<bits/stdc++.h> #define int long long using namespace std; int n,m,maxh,h[1000031]; bool check(int x){ int sum=0; for(int i=1;i<=n;i++) if(h[i]>x) sum+=h[i]-x; return sum>=m; } signed main(){ cin>>n>>m; for(int i=1;i<=n;i++) cin>>h[i],maxh=max(maxh,h[i]); int l=-1,r=maxh+1; while(l+1<r){ int mid=(l+r)>>1; if(check(mid)) l=mid; else r=mid; } cout<<l; return 0; }
T2
二分 \(l\) 的值,边界为 \(L=0,R=\max{\{a_i\}}\)(注意 \(L\) 为 \(0\),这样可以免去不必要的特判)。
每次枚举到一个 \(mid\),则当前段数为 \(\sum^{n}_{i=1} \lfloor \dfrac{a_i}{mid} \rfloor\),判断其是否 \(\ge m\) 即可。
#include<bits/stdc++.h> #define int long long using namespace std; int n,k,l[100031]; bool check(int x){ int sum=0; for(int i=1;i<=n;i++) sum+=l[i]/x; return sum>=k; } signed main(){ cin>>n>>k; for(int i=1;i<=n;i++) cin>>l[i]; int l=0,r=1e8+1; while(l+1<r){ int mid=(l+r)>>1; if(check(mid)) l=mid; else r=mid; } cout<<l; return 0; }
习题
T3
首先读入字符串,分离并计算出做一个汉堡需要的 \(B,S,C\)。记读入的已有材料数分别为 \(nb,ns,nc\),需要的钱数分别为 \(mb,ms,mc\),已有钱数为 \(money\)。
二分能做出的汉堡个数,边界为 \(L=-1,R=money+\max{(nb,ns,nc)}\)。对于每个 \(mid\),计算出除去已有材料后还需要花的钱,与 \(money\) 作比较即可。
#include<bits/stdc++.h> #define int long long using namespace std; string str; int b,s,c; int nb,ns,nc; int mb,ms,mc; int money; bool check(int x){ int sum=0; if(x*b>nb) sum+=(x*b-nb)*mb; if(x*s>ns) sum+=(x*s-ns)*ms; if(x*c>nc) sum+=(x*c-nc)*mc; return sum<=money; } signed main(){ cin>>str; cin>>nb>>ns>>nc; cin>>mb>>ms>>mc; cin>>money; for(int i=0;str[i];i++){ if(str[i]=='B') b++; else if(str[i]=='S') s++; else c++; } int l=-1,r=money+max(nb,max(ns,nc))+1; while(l+1<r){ int mid=(l+r)>>1; if(check(mid)) l=mid; else r=mid; } cout<<l; return 0; }
T4
记需要 \(x\) 轮才能满足所有人的要求,且所有人共需要玩 \(s\) 轮游戏。
由定义可知 \(s=\sum^{n}_{i=1} a_i\),并且由题意有 \((n-1)x \ge s\)。
则可以二分 \(x\) 的值,边界为 \(L=\max{\{a_i\}}-1,R=s+1\)。
每次枚举到一个 \(mid\),就按照上式检查即可。
#include<bits/stdc++.h> #define int long long using namespace std; int n,s,m,a[100031]; signed main(){ cin>>n; for(int i=1;i<=n;i++) cin>>a[i],s+=a[i],m=max(m,a[i]); int l=m-1,r=s+1; while(l+1<r){ int mid=(l+r)>>1; if(mid*(n-1)>=s) r=mid; else l=mid; } cout<<r; return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】