整数二分模板:数的范围
二分的本质不是单调性,而是二分出能满足某种性质使得将整数分成两半。
思考:模板题,模板记熟就能做
#include<iostream>
using namespace std;
int n,q;
const int N = 1e5+10;
int a[N];
int main( ){
cin>>n>>q;
for(int i=0;i<n;i++)cin>>a[i];
while(q--){
int k;cin>>k;
int l = 0,r = n-1;
while(l<r){
int mid = (l+r)>>1;
if(a[mid]>=k)r=mid;
else l=mid+1;
}
if(a[r]==k)cout<<r<<" ";
else cout<<-1<<" ";
l = 0,r = n-1;
while(l<r){
int mid = (l+r+1)>>1;
if(a[mid]<=k)l=mid;
else r=mid-1;
}
if(a[l]==k)cout<<l<<'\n';
else cout<<-1<<'\n';
}
return 0;
}
冶炼金属
c++除法是下取整的
根据评测用例,可以看出需要设计 nlogn 的算法,也就是要用到二分。关键是二分时需要找到大于等于某值的上限和下限,边界条件确定比较细节和关键。思路:每次输入 A 和 B,通过二分来找到满足条件的V的上界和下界,min_v 为所有下界的最大值,max_v 相反。
#include<bits/stdc++.h>
using namespace std;
const int inf =0x3f3f3f3f;
int n;
int Min_v = 0,Max_v=inf;
int main( ){
cin>>n;
while(n--){
int a,b;
cin>>a>>b;
int l = 0,r = a+1;
while(l<r){
int mid = (l+r)>>1;
if(a/mid<=b)r=mid;
else l=mid+1;
}
Min_v = max(Min_v,r);
l = 0,r = a+1;
while(l<r){
int mid = (l+r+1)>>1;
if(a/mid>=b)l=mid;
else r=mid-1;
}
Max_v = min(Max_v,l);
}
cout<<Min_v<<' '<<Max_v<<'\n';
return 0;
}
浮点二分:数的三次方根
思路:浮点二分不用模板直接做,细节是保留 6 位小数 while 要到 1e-8,保留 4 位 while 要到 1e-6,多两位,printf lf 默认保留 6位小数。
#include<iostream>
using namespace std;
double n;
int main( ){
cin>>n;
double l = -10000,r = 10000;
while(r-l>=1e-8){
double mid = (l+r)/2;
if(mid*mid*mid<=n)l = mid;
else r = mid;
}
printf("%.6f",r);
return 0;
}