有一类常见问题叫做最小值最大化或者最大值最小化。这类问题一般是用二分搜索来解决。
首先二分搜索解决的问题必须具备单调性这个性质,这是使用二分搜索的必要条件,我们分析两个问题。
1.最小值最大化:我们假设x为最大的最小值,那么x-1是满足条件的,但他并不满足最大,x+1是不满足条件的,假设我们左边界是L,右边界是R,我们二分一个答案ans,ans为最后一个满足条件的数,我们是不是可以类比二分搜索(一)中的last_less_equal()或者last_less()这个问题和这两者是差不多的。可以先阅读我的另一篇博文:二分搜索(一)——各种二分
2.最大值最小化:我们假设x为最小的最大值,那么x-1是不满足条件的,x+1是满足条件的,但他不满足最小,假设我们左边界是L,右边界是R,我们二分一个答案ans,ans为第一个满足条件的数,我们是不是可以类比二分搜索(一)中的lower_bound()或者upper_bound()这个问题和这两者是差不多的。
所以综上所述并根据我在二分搜索(一)——各种二分中的描述:最小值最大化的二分区间是右闭左开(L,R],每次二分的中心为M=(L+R+1)/2;最大值最小化的二分区间是左闭右开,[L,R),每次二分的中心为M=(L+R)/2。
例题1:LA3971-3971——Assemble
题目意思:你有b块钱,想要组装一台电脑。给出n个配件格子的种类,品质因子和价格,要求每种类型的配件各买一个,总价格不超过b,且品质最差的配件的品质因子尽量大。
思路:这很明显是一个最小值最大化的问题,这道题还用到map对物品按名称进行分类,注意多组输入,要对上一组的数据进行清空,我们可以看出二分边界L=-1,R=maxq(所有商品中品质因子的最大值。),也就是右闭左开区间(L,R],我们搜索最后一个满足条件的ans值,具体看代码吧。
代码:
#include<bits/stdc++.h> using namespace std; const int N=1000+7; map<string,int>mp; struct node{ int p,q; }; vector<node>a[N]; int cnt=0,n,b; int check(int M){ long long sum=0; for(int i=0;i<cnt;i++){ int minn=b+10; for(int j=0;j<(int)a[i].size();j++){ if(a[i][j].q>=M){ minn=min(minn,a[i][j].p); } } sum+=minn; if(sum>b) return 0; } return 1; } int main(){ int T;cin>>T; while(T--){ cin>>n>>b; for(int i=0;i<cnt;i++) a[i].clear(); cnt=0; int L=-1,R=0; for(int i=0;i<n;i++){ string type,name; int p,q; cin>>type>>name>>p>>q; if(mp.count(type)==0){ mp[type]=cnt++; } R=max(R,q); a[mp[type]].push_back({p,q}); } while(L<R){ int M=(L+R+1)/2; if(check(M)) L=M; else R=M-1; } cout<<R<<endl; } return 0; }