二分答案
- 貌似题目让你求啥就要对什么东西进行二分
实数二分
-
注意精度,如果要求输出两位小数,建议二分到三、四位
-
还是注意精度,P1542不用 long double 都过不去
P1024 [NOIP2001 提高组] 一元三次方程求解
-
对根所在区间进行二分
-
因为 ’根与根的差的绝对值
‘,所以枚举 中的每个整数即可,二分的区间的 分别是 -
进行二分的条件:
-
如果
,且 ,那么方程的其中一个根就是 -
如果
,暂时不管他,在枚举到 时再输出,防止重复
-
-
关于
:-
由题目得,如果
,则在 内存在一个根 -
所以如果
,就让 ,因为此时根在 中,反之
-
代码
#include <bits/stdc++.h> #define int long long using namespace std; const int INF=1e9; const double ACC=1e-7; int cnt; double a,b,c,d; double check(double x){ return 1.0*a*x*x*x+1.0*b*x*x+1.0*c*x+d; } signed main(){ // freopen("1.in","r",stdin); cin>>a>>b>>c>>d; for(int i=-100;i<100;i++){ double l=i,r=i+1; double x=check(l),y=check(r); if(!x){ printf("%.2lf ",double(l)); cnt++; continue; }else{ if(x*y>=0) continue; while(r-l>ACC){ double mid=(l+r)/2; if(check(mid)*check(l)<=0) r=mid; else l=mid; } printf("%.2lf ",l); cnt++; } if(cnt==3) break; } }
P1542 包裹快递
-
对速度进行二分
-
‘最大的最小’ 意味着要在当前值符合条件的情况下把右指针左移(在速度更小的区间里寻找符合条件的值)
-
题目卡精度卡的很严,必须要用 long double
-
关于
:-
题目要求最大速度的最小值,由样例解释可得,每段路程的速度是可变的,只要全程的最大速度最小即可
-
二分到的一个速度不符合条件,意味着至少有一段路程,用最大速度(二分到的速度)跑,仍然赶不上截止期限
-
代码
#include <bits/stdc++.h> #define int long long using namespace std; const int INF=1e9; const int N=2e5+10; int n; int x[N],y[N],s[N],sum; long double l,r; bool check(long double max_sp){ long double ti=0; for(int i=1;i<=n;i++){ if(ti+1.0*s[i]/max_sp>y[i]) return 0; else ti+=1.0*s[i]/max_sp; if(ti<x[i]) ti=x[i]; } return 1; } signed main(){ // freopen("1.in","r",stdin); cin>>n; for(int i=1;i<=n;i++){ cin>>x[i]>>y[i]>>s[i]; sum+=s[i]; } l=0; r=1e9; while(r-l>0.0001){ long double mid=(l+r)/2; if(check(mid)) r=mid; else l=mid; } printf("%.2Lf\n",l); }
P1577 切绳子
-
对切割成的绳子的长度进行二分
-
输入的绳长都是两位小数,干脆把他们都
,把这道题转化成整数二分来做 -
关于
:-
对于二分出来的一个长度,枚举每一根绳子,把每根绳子能割出来的绳子数相加
-
如果加和
,说明当前长度太长,令 -
反之令
-
代码
#include <bits/stdc++.h> using namespace std; int n,k; double in; int len[10010]; int judge(int length){ int cnt=0; for(int i=1;i<=n;i++) cnt+=len[i]/length; return cnt>=k; } int main(){ // freopen("1.in","r",stdin); cin>>n>>k; for(int i=1;i<=n;i++){ cin>>in; len[i]=in*100; } int l=0; int r=1e9; int res=0; while(l<r){ int mid=l+(r-l)/2; if(mid==0) break; if(judge(mid)){ l=mid+1; res=mid; } else r=mid; } printf("%.2lf",res*1.0/100); }
整数二分
P1824 进击的奶牛
-
对两头牛间的最近距离进行二分
-
关于
:-
贪心,用
记录上一头牛的位置,一旦这个牛棚距离 的距离 二分到的最小距离,就 ,并且把 移动到该牛棚 -
采用贪心能保证牛棚在该 ‘最小距离’ 下尽可能多的放牛
-
代码
#include <bits/stdc++.h> using namespace std; int pos[100010]; int n,c; bool judge(int len){ int cnt=1; int p=1; for(int i=2;i<=n;i++){ if(pos[i]-pos[p]>=len){ cnt++; p=i; } } return cnt>=c; } int main(){ // freopen("1.in","r",stdin); cin>>n>>c; for(int i=1;i<=n;i++) cin>>pos[i]; sort(pos+1,pos+1+n); int l=0; int r=pos[n]; int res=r; while(l<r){ int mid=l+(r-l)/2; if(judge(mid)){ res=mid; l=mid+1; } else r=mid; } cout<<res; }
P1182 数列分段 Section II
-
对每段的和的最大值进行二分
-
因为求的是 ’最大值最小‘ ,所以当前值符合条件的情况下:
-
如果根据当前最大值分的快多于
,就将 右移,增大最大值,使数列能被分为更少的块 -
反之将
左移,使分的块更多或在块数符合条件的情况下使最大值最小
-
代码
#include <bits/stdc++.h> #define int long long using namespace std; const int INF=1e9; int n,m; int a[100001]; int l,r; bool check(int maxi){ int sum=0,cnt=0; for(int i=1;i<=n;i++){ if(a[i]>maxi) return 0; if(sum+a[i]>maxi){ sum=a[i]; cnt++; }else sum+=a[i]; } return cnt>=m; } signed main(){ // freopen("1.in","r",stdin); cin>>n>>m; for(int i=1;i<=n;i++){ cin>>a[i]; r+=a[i]; l=max(l,a[i]); } while(l<r){ int mid=(l+r)/2; if(check(mid)) l=mid+1; else r=mid; // cout<<l<<" "<<r<<"\n"; } cout<<l<<"\n"; }
P2440 木材加工
-
对分成的木头的长度进行二分
-
因为有可能根本分不出
段来,所以 初始为 ,相应的,while(l < r)
改为while(l+1 < r)
-
部分与 P1577 切绳子 差不多,翻到上面看就行
代码
#include <bits/stdc++.h> #define int long long using namespace std; const int INF=1e9; int n,k; int len[100001]; int check(int x){ int cnt=0; for(int i=1;i<=n;i++) cnt+=(len[i]/x); return cnt; } signed main(){ // freopen("1.in","r",stdin); cin>>n>>k; for(int i=1;i<=n;i++) cin>>len[i]; int l=0,r=1e18; while(l+1<r){ int mid=(l+r)/2; if(check(mid)>=k) l=mid; else r=mid; } cout<<l<<"\n"; }
P1873 [COCI 2011/2012 #5] EKO / 砍树
- 对锯子的最大高度进行二分
代码
#include <bits/stdc++.h> using namespace std; long long hei[1000010]; long long n,m; bool judge(long long len){ long long cnt=0; long long p=0; for(long long i=1;i<=n;i++){ if(hei[i]>len) cnt+=hei[i]-len; } return cnt>=m; } int main(){ // freopen("1.in","r",stdin); cin>>n>>m; for(long long i=1;i<=n;i++) cin>>hei[i]; sort(hei+1,hei+1+n); long long l=0; long long r=hei[n]; while(l+1<r){ long long mid=l+(r-l)/2; if(judge(mid)) l=mid; else r=mid; } cout<<res; }
P1083 [NOIP2012 提高组] 借教室
-
对有多少订单符合要求进行二分
-
关于
:判断是否有订单不满足要求时用差分进行处理bool check(int x){ memset(temp,0,sizeof(temp)); for(int i=1;i<=x;i++){ temp[s[i]]+=d[i]; temp[t[i]+1]-=d[i]; } for(int i=1;i<=n;i++){ temp[i]+=temp[i-1]; if(temp[i]>r[i]) return 0; } return 1; }
代码
#include <bits/stdc++.h> #define int long long using namespace std; const int INF=1e9; const int N=1e6+10; int n,m; int r[N]; int d[N],s[N],t[N]; int temp[N]; bool check(int x){ memset(temp,0,sizeof(temp)); for(int i=1;i<=x;i++){ temp[s[i]]+=d[i]; temp[t[i]+1]-=d[i]; } for(int i=1;i<=n;i++){ temp[i]+=temp[i-1]; if(temp[i]>r[i]) return 0; } return 1; } signed main(){ // freopen("1.in","r",stdin); cin>>n>>m; for(int i=1;i<=n;i++) cin>>r[i]; for(int i=1;i<=m;i++) cin>>d[i]>>s[i]>>t[i]; if(check(m)){ cout<<"0\n"; return 0; } int l=1,r=m; while(l<r){ int mid=(l+r)/2; if(!check(mid)) r=mid; else l=mid+1; } cout<<"-1\n"<<r<<"\n"; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话