文章目录
- 模板一:
- 模板二:
-
- 使用场景:
- 解释:
- 例题:
-
- [[Building an Aquarium](https://codeforces.com/problemset/problem/1873/E)](#Building an Aquarium)
模板一:
cpp
while(l < r){
int mid = l + r >> 1;
while(check(mid)) r = mid;
else l = mid +1;
}
使用场景:
此模板用于找出满足条件的最小值,即尽量往左找。
解释:
当mid满足条件时,执行 r = m i d r=mid r=mid,将区间往左缩小,直到l==r时候找到答案 。
例题:
数的范围
题意:
给定一个按照升序排列的长度为 n n n的整数数组,以及 q q q个查询。对于每个查询,返回一个元素 k k k的起始位置和终止位置(位置从 0开始计数)。如果数组中不存在该元素,则返回 − 1 − 1 -1 -1 −1−1。
代码:
cpp
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=100010;
int n,m;
int a[N];
int main()
{
cin>>n>>m;
for(int i=0;i<n;i++) cin>>a[i];
while(m--)
{
int x;
cin>>x;
int l=0,r=n-1;
while(l<r)
{
int mid=(l+r)>>1;
if(a[mid]>=x) r=mid;
else l=mid+1;
}
if(a[l]!=x)
{
cout<<"-1 -1"<<endl;
}
else
{
cout<<l<<" ";
l=0,r=n-1;
while(l<r)
{
int mid=(l+r+1)>>1;
if(a[mid]<=x) l=mid;
else r=mid-1;
}
cout<<l<<endl;
}
}
return 0;
}
模板二:
cpp
while(l < r){
int mid = (l + r + 1) >> 1;//提醒:mid的更新方式不太一样
while(check(mid)) l = mid;
else r = mid - 1;
}
使用场景:
用于找出满足条件的最大值,即尽量往右找。
解释:
当 m i d mid mid满足条件时,执行操作 l = m i d l = mid l=mid,此时区间会向右边缩小。
例题:
Building an Aquarium
题意:
你喜欢养鱼,所以你决定建造一个水族馆。你有一块由 n n n 根柱子组成的珊瑚,其中 i i i 根柱子高 a i a _{i} ai 个单位。之后,你将在珊瑚周围建造一个水族箱,具体如下:
- 选取一个整数 h h h --水箱的高度。在水箱两侧建造高度为 h h h的墙壁。
- 然后,在水箱中注满水,使每一列的高度都是 h h h ,除非珊瑚的高度超过 h h h ,否则这一列不需要注水。
例如, a = [ 3 , 1 , 2 , 4 , 6 , 2 , 5 ] a=[3,1,2,4,6,2,5] a=[3,1,2,4,6,2,5] 和高度为 h = 4 h=4 h=4 ,最终总共需要使用 w = 8 w=8 w=8 个单位的水,如图所示。
你最多可以用 x x x 个单位的水来装满水箱,但你想尽可能建造最大的水箱。你能选择的 h h h 的最大值是多少?
代码:
cpp
#include<iostream>
#include<algorithm>
#include<vector>
#include<cstring>
#define int long long
using namespace std;
void solve(){
int n,x;
cin>>n>>x;
vector<int> a(n);
for(int i=0;i<n;i++) cin>>a[i];
int l=0;
int r=2000000007;
while(l<r){
int ans=0;
int mid=(r+l+1)/2;
for(int i=0;i<n;i++) ans+=max((long long)0,mid-a[i]);
if(ans<=x) l=mid;
else r=mid-1;
}
cout<<l<<endl;
}
signed main(){
int t;
cin>>t;
while(t--) solve();
return 0;
}
由于本人写二分时,范围总是出错,总是把两个mid的更新方式搞混,特写此文章加深记忆。