是跟着这篇写的笔记
二分查找 & 二分答案 万字详解,超多例题,带你学透二分。-CSDN博客
二分相关的知识点们
vector
int bina(vector<int>a,int x){
int l=0,r=a.size()-1;
while(l<r){
int mid=(l+r)>>1;
if(a[mid]>=x)r=mid;
else l=mid+1;
}
if(a[l]!=x)return -1;
else return l;
}
lower_bound 大于等于
upper_bound 大于
lower_bound(左,右,x)-数组[0]
,意思是在【左,右)找,减头从而得到下标
lower_bound(a+1,a+n+1,x)-a;
lower_bound(a.begin(),a.end(),x)-a.begin();//不能用-a,类型不一样
整数(这里先全用lower_bound力)
P2249 【深基13.例1】查找 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
怎么都过不去
P1102 A-B 数对 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
try1:(1)每种减把减数,被减数,差放在结构体里
(2)排序(3)二分 nm
try2: (1)排序(2)对于每个数查找 nm(nm就过不了#3测试点,原来也二分查找右端点nlgn)
灵机一动,用upper_bound
#include<iostream>
using namespace std;
#include<algorithm>
int main(){
long long a[200001];
long long n;scanf("%lld",&n);long long c;scanf("%lld",&c);
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
}
sort(a+1,a+n+1);
long long ans=0;
for(long long i=1;i<=n-1;i++){
long long wei1=lower_bound(a+1,a+n+1,a[i]+c)-a;
long long wei2=upper_bound(a+1,a+n+1,a[i]+c)-a;
ans+=wei2-wei1;
}
printf("%lld",ans);
}
try3:(1)统计每个数出现次数(2)对于每个数+c 由于是直接访问,n
错以为2^30是8*2^10,这数组开不到这么大,失败
#include<iostream>
using namespace std;
int book[1073741828]={0};//每个数出现了几遍
int main(){
int a[200001];
int n;cin>>n;int c;cin>>c;
for(int i=1;i<=n;i++){
cin>>a[i];
book[a[i]]++;
}
int ans=0;
for(int i=1;i<=n;i++){
ans+=book[a[i]+c];
}
printf("%d",ans);
}
P1678 烦恼的高考志愿 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
注意比分数线最高的还要高和比最低的还要低的情况,我把0到100001全设为INF
#define INF 0x3f3f3f3f
#include<iostream>
using namespace std;
#include<algorithm>
long mschool[100001];
long nstu[100001];
long m,n;
long solu(long i){
long mid=lower_bound(mschool+1,mschool+m+1,nstu[i])-mschool;///
return min(abs(mschool[mid]-nstu[i]),min(abs(mschool[mid-1]-nstu[i]),abs(mschool[mid+1]-nstu[i])));
}
int main(){
long long ans=0;
cin>>m>>n;
for(long i=0;i<=100001;i++)mschool[i]=INF;
for(long i=1;i<=m;i++)cin>>mschool[i];
sort(mschool+1,mschool+m+1);
for(long i=1;i<=n;i++){
cin>>nstu[i];
ans+=solu(i);
}
cout<<ans;
}
#include<iostream>
using namespace std;
#include<algorithm>
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
//测试询问最后一个元素
int main(){
long n;int q;
cin>>n>>q;
int a[100001];
memset(a,INF,sizeof(a));
for(long i=0;i<n;i++)cin>>a[i];
while(q--){
int k;cin>>k;
long wei1=lower_bound(a,a+n,k)-a;//这里注意
long wei2=upper_bound(a,a+n,k)-a;
if(a[wei1]!=k){
cout<<-1<<" "<<-1;
}
else{
cout<<wei1<<" "<<wei2-1;
}
if(q!=0)cout<<endl;
}
}
P1873 [COCI 2011/2012 #5] EKO / 砍树 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
也没有看,最后l-1或者r-1两种
至于加一还是减一是样例代出来的
#include<iostream>
using namespace std;
#include<algorithm>
long n;
long long m;
long h_tree[1000001];
bool check(long mid){
long long temp=0;
for(long i=1;i<=n;i++){
if(h_tree[i]>mid){
temp+=h_tree[i]-mid;
}
}
if(temp<m)return true;
else return false;
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++)cin>>h_tree[i];
long l=0,r=400000;
while(l<r){
long mid=(l+r)/2;
if(check(mid))r=mid;
else l=mid+1;
}
cout<<r-1;
}
P2440 木材加工 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
check怎么不写反:
if(mid>=ans)
temp+=的分母大
temp<k
这样一步步代,或者mid大,截的每一段大,段数小
#include<iostream>
using namespace std;
#include<algorithm>
int n;long k;
long mu[100001];
bool check(long mid){
long temp=0;
for(int i=1;i<=n;i++){
temp+=mu[i]/mid;
}
if(temp<k)return 1;
else return 0;
}
int main(){
cin>>n>>k;
for(int i=1;i<=n;i++)cin>>mu[i];
long l=1,r=100000000;
while(l<r){
long mid=(l+r)/2;
if(check(mid))r=mid;
else l=mid+1;
}
cout<<r-1;
}
P2678 [NOIP2015 提高组] 跳石头 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
没过
实数
P1163 银行贷款 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
#include<iostream>
using namespace std;
double w0;
double wper;
int mon;
bool check(double mid){
double temp=w0;//防止改变
for(int i=1;i<=mon;i++){
temp=temp+temp*mid-wper;
}
if(temp>0)return 1;
return 0;
}
int main(){
cin>>w0>>wper>>mon;
double r=4;
double l=0;
while(r-l>1e-5){//自己定的更精细的区间,之后打印再保留几位
double mid=(l+r)/2;
if(check(mid))r=mid;
else l=mid;
}
printf("%.1lf",l*100);
}
奇函数单调增,正负一起找
#include<iostream>
using namespace std;
double sov;
bool check(double mid){
return mid*mid*mid>sov;
}
int main(){
cin>>sov;
double l=-10000,r=10000;
while(r-l>1e-7){
double mid=(l+r)/2;
if(check(mid))r=mid;
else l=mid;
}
printf("%.6lf",l);
}
P1024 [NOIP2001 提高组] 一元三次方程求解 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
只能说侥幸过,这个给的数据让人不爽
#include<iostream>
using namespace std;
double a,b,c,d;
double f(double x){
return a*x*x*x+b*x*x+c*x+d;
}
bool check(double l,double r,double mid){
if(f(l)*f(mid)<0)return true;
else return false;
}
int main(){
cin>>a>>b>>c>>d;
bool flag=1;
for(int i=-100;i<=99;i++){
if(f(i)*f(i+1)<=0){
if(f(i)==0){//左端是根就输出
if(flag==1)flag=0;
else cout<<" ";
printf("%.2lf",1.0*i);
continue;
}
else if(f(i+1)!=0){//为了不多空格
double l=i,r=i+1;
while(r-l>1e-5){
double mid=(l+r)/2;
if(check(l,r,mid))r=mid;
else l=mid;
}
if(flag==1)flag=0;
else cout<<" ";
printf("%.2lf",l);
}
}
}
}
三分相关的知识点们
开始看错题了写的数学打表二次函数在区间的最小值
#include<iostream>
using namespace std;
int main(){
int t;
cin>>t;
while(t--){
double a,b,c;cin>>a>>b>>c;
if(a==0){
if(b>=0)printf("%.4lf",c);
else printf("%.4lf",1000*b+c);
}
else if(a>0){
if(b>=0)printf("%.4lf",c);//对称轴在0左
else if(2000*a+b<=0){//对称轴在1000右
printf("%.4lf",1000*b+c);
}
else {
printf("%.4lf",c*c-4*a*b);
}
}
else {
if(1000*a+b<=0)//500左
{
printf("%.4lf",1000*b+c);
}
else printf("%.4lf",c);//500右
}
if(t!=0)cout<<endl;
}
}
try1:嘿嘿想数学一样求交点,再比较几个交点的最小值
try2: