二分

最近碰到的二分题有点多,而且方法都不同,拿来说一下,顺便给自己做下总结

模板1:

复制代码
while (l < r) { int mid = l + r >> 1; //(l+r)/2 if (check(mid)) r = mid; // check()判断mid是否满足性质 else l = mid + 1; }
复制代码

模板2:

复制代码
while (l < r) { int mid = l + r + 1 >> 1; //(l+r+1)/2 if (check(mid)) l = mid; else r = mid - 1; }
复制代码

第一个模板是尽量往左找目标,第二个模板是尽量往右找目标。

只要是往左找答案,就用第一个模板,mid不用加一,r=mid,l加一;
只要是往右找答案,就用第二个模板,mid要加一,l=mid,r要减一;

浮点二分:

 

复制代码
while(r-l>1e-5) //需要一个精度保证 { double mid = (l+r)/2; if(check(mid)) l=mid; //或r=mid; else r=mid; //或l=mid; }
复制代码

 

 

 

二分查找与普通二分答案:一般是套用第二个模板,最终得到的L就是最终答案:
最小值最大,第二个模板,最大值最小,第一个模板

 额外补充一点,二分题很多都要开到long long所以这一点一定要注意

 

复制代码
//木材加工:https://www.luogu.com.cn/problem/P2440 #include<bits/stdc++.h> using namespace std; const int N=1e5+10; long long n,k,a[N],res,l,r; bool check(int u) { int num=0; for(int i=0;i<n;i++) num+=(a[i]/u); if(num>=k) return true; else return false; } int main() { cin>>n>>k; for(int i=0;i<n;i++) cin>>a[i],r=max(r,a[i]); while(l<r){ int mid=l+r+1>>1; if(check(mid)) l=mid; else r=mid-1; } cout<<l; return 0; }
复制代码

 

复制代码
//Primes on Interval: https://www.luogu.com.cn/problem/CF237C #include<bits/stdc++.h> using namespace std; const int N=1e6+10; int n,m,k,res,num,p[N],prime[N]; bool vis[N]; bool check(int u)//滑动窗口判断素数 { int hh=n-1,tt=n,cnt=0;//建立队头队尾 while(hh-tt+1<u){//找到区间的第一个头 hh++; if(!vis[hh]) cnt++;//先++; } while(hh<=m){ if(cnt<k) return false;//判断 hh++; if(!vis[hh]) cnt++;//向前滑动一位,并判断 tt++; if(!vis[tt-1]) cnt--;//队尾也向前,如果划掉素数了就要减 } return true; } int main() { cin>>n>>m>>k; vis[1]=true; for(int i=2;i<=m;i++){ if(!vis[i]) prime[++num]=i,p[i]=i; for(int j=1;prime[j]<=m/i;j++){ vis[i*prime[j]]=true; if(!(i%prime[j])) break; } } if(!check(m-n+1)) return cout<<-1,0; int l=1,r=m+1; while(l<r){//模板一,找小值 int mid=l+r>>1; if(check(mid)) r=mid; else l=mid+1; } cout<<r; return 0; }
复制代码

 

复制代码
//借教室:https://www.luogu.com.cn/problem/P1083 #include<bits/stdc++.h> using namespace std; const int N=1e6+10; long long c[N],need[N],st[N],ed[N],n,m,res,a[N],p[N]; bool check(int u) { memset(c,0,sizeof c); for(int i=1;i<=u;i++) c[st[i]]+=need[i],c[ed[i]+1]-=need[i]; for(int i=1;i<=n;i++){ p[i]=p[i-1]+c[i]; if(p[i]>a[i]) return false; } return true; } int main() { cin>>n>>m; for(int i=1;i<=n;i++) cin>>a[i]; for(int i=1;i<=m;i++) cin>>need[i]>>st[i]>>ed[i]; if(check(m)) return cout<<0,0; int l=1,r=m; //二分最左端 while(l<r){ int mid=l+r>>1; if(check(mid)) l=mid+1; else r=mid; } cout<<-1<<endl<<l; return 0; }
复制代码
复制代码
//Present:https://www.luogu.com.cn/problem/CF460C //最小值最大 #include<bits/stdc++.h> #define ll long long using namespace std; const int N=1e5+10; int n,m,w; ll res,l=2e9,r=2e9,a[N],c[N]; bool check(int h) { ll day=0,now=0; for(int i=1;i<=n;i++){ now+=c[i]; if(now<h){ day+=h-now; c[i]+=h-now; if(i+w<=n) c[i+w]-=h-now; now+=h-now; } } return day<=m; } int main() { cin>>n>>m>>w; for(int i=1;i<=n;i++){ cin>>a[i]; l=min(l,a[i]); r=max(r,a[i]); c[i]=a[i]-a[i-1]; } //模板二 while(l<r){ int mid=l+r+1>>1; if(check(mid)) l=mid; else r=mid-1; for(int i=1;i<=n;i++) c[i]=a[i]-a[i-1]; } cout<<l<<endl; return 0; }
复制代码

 

复制代码
//[COCI 2011/2012 #5] EKO / 砍树:https://www.luogu.com.cn/problem/P1873 #include<bits/stdc++.h> using namespace std; const int N=1e6+10; long long n,m,res,a[N],l,r; bool check(int u) { long long num=0; for(int i=0;i<n;i++) if(a[i]>u) num+=a[i]-u; return num>=m; } int main() { cin>>n>>m; for(int i=0;i<n;i++) cin>>a[i],r=max(r,a[i]); while(l<r){ long long mid=l+r+1>>1; if(check(mid)) l=mid; else r=mid-1; } cout<<l; return 0; }
复制代码

 

复制代码
//最大化最小值 //[NOIP2015 提高组] 跳石头:https://www.luogu.com.cn/problem/P2678 #include<bits/stdc++.h> #define ll long long using namespace std; const int N=1e5+10; ll n,m,st,a[N],res,l,r,p[N]; bool check(int u) { ll num=0; for(int i=0;i<=n+1;i++) p[i]=a[i]; for(int i=1;i<=n+1;i++) if(p[i]-p[i-1]<u) p[i]=p[i-1],num++; return num<=m; } int main() { cin>>st>>n>>m; l=0,r=st,a[0]=0,a[n+1]=st; for(int i=1;i<=n;i++) cin>>a[i]; while(l<r){ ll mid=l+r+1>>1; if(check(mid)) l=mid; else r=mid-1; } cout<<l; return 0; }
复制代码

 

复制代码
//路标放置:https://www.luogu.com.cn/problem/P3853 //最大值最小,模板一 //难点在于check函数 //来自大佬的题解: //我们可以想象,我们已知了这条路上的所有的路标,我们从头开始枚举两两相邻的路标的间距. //如果大于G,那么已经不符合G为最大距离的条件了,为了使G满足,我们就可以在前一个路标前面G米处加一个路标,这样与前面一个就符合条件了. //再判断新设的路标和后面的路标是否距离小于G,如果不,继续重复操作设置新路标 //当新设的路标数已经超过题目所给最大增设值时,如果还有路标不满足G,但已经不能设置新路标了,所以该G值就不满足条件。相反,则G成立。 #include<bits/stdc++.h> using namespace std; const int N=1e7+10; int a[N],res,n,m,k,l,r,op; bool vis[N]; bool check(int u) { int num=m,now=0; for(int i=0;i<=op;i++){ if(num<0) break; if(a[i]-now<=u) now=a[i]; else{ now+=u; i--; num--; } } return num>=0; } int main() { cin>>op>>n>>m; for(int i=0;i<n;i++) cin>>a[i],r=max(r,a[i]-a[i-1]),vis[a[i]]=true; while(l<r){ int mid=l+r>>1; if(check(mid)) r=mid; else l=mid+1; } cout<<r; return 0; }
复制代码

浮点数二分:

 

复制代码
//浮点数二分: //不会做,纯纯的理论数学,不会搞公式 //银行贷款:https://www.luogu.com.cn/problem/P1163 #include<bits/stdc++.h> #define EPS 1e-9 using namespace std; const int N=1e5+10; double now,next1,need,l,r,res; bool check(double u) { return (pow(1.0/(1.0+u),need)>=1-now/next1*u); } int main() { cin>>now>>next1>>need; l=0,r=10; while(r-l>=EPS){ double mid=(l+r)/2; if(check(mid)) r=mid; else l=mid; } printf("%.1lf",l*100); return 0; }
复制代码

 

复制代码
//浮点数二分 //kotori的设备:https://www.luogu.com.cn/problem/P3743 #include<bits/stdc++.h> #define EPS 1e-5 using namespace std; const int N=6e5+10; long double res,l,r,a[N],b[N],n,m; bool check(long double u) { long double sum=u*m,tmp=0; for(int i=0;i<n;i++) if(b[i]/a[i]-u<EPS) tmp+=(u-b[i]/a[i])*a[i]; if(tmp-sum<=EPS) return true; else return false; } int main() { cin>>n>>m; double asum=0.0; for(int i=0;i<n;i++){ cin>>a[i]>>b[i]; asum+=a[i]; } if(asum<=m) return cout<<-1,0;//这一步很关键 l=0.000,r=1e10; while(r-l>EPS){ long double mid=(l+r)/2; if(check(mid)) l=mid; else r=mid; } cout<<l; return 0; }
复制代码

 


__EOF__

本文作者Sakurajimamai
本文链接https://www.cnblogs.com/o-Sakurajimamai-o/p/17487420.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   o-Sakurajimamai-o  阅读(58)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
-- --
点击右上角即可分享
微信分享提示