A06 二分答案
视频链接:A06 二分答案 最好的套路_哔哩哔哩_bilibili
#include <iostream> #include <cstring> #include <algorithm> using namespace std; typedef long long LL; const int N = 100005; int n, k, a[N]; bool check(int x){ LL y=0; //段数 for(int i=1;i<=n;i++) y+=a[i]/x; return y>=k; //x小,y大 } int find(){ int l=0, r=1e8+1; while(l+1<r){ int mid=l+r>>1; if(check(mid)) l=mid; //最大化 else r=mid; } return l; } int main(){ scanf("%d%d",&n,&k); for(int i=1; i<=n; i++)scanf("%d",&a[i]); printf("%d\n",find()); return 0; }
2. Luogu P2678 [NOIP2015 提高组] 跳石头
#include <iostream> #include <cstring> #include <algorithm> using namespace std; int L, n, M, a[500005]; bool check(int x){ int last=0,cnt=0; for(int i=1;i<=n+1;i++) if(a[i]-a[last]<x) cnt++;//贪心 else last=i; return cnt<=M; //x小,cnt小 } int find(){ int l=0, r=1e9+1; while(l+1<r){ int mid=l+r>>1; if(check(mid)) l=mid; //最大化 else r=mid; } return l; } int main(){ scanf("%d%d%d",&L,&n,&M); for(int i=1;i<=n;i++)scanf("%d",&a[i]); a[n+1]=L; //右边界 printf("%d\n",find()); return 0; }
3. Luogu P1314 [NOIP2011 提高组] 聪明的质监员
#include <iostream> #include <cstring> #include <algorithm> using namespace std; typedef long long LL; const int N=200010; int n,m, w[N],v[N],l[N],r[N]; LL s,sn[N],sv[N],ans=1e18; bool check(int W){ memset(sn,0,sizeof sn); memset(sv,0,sizeof sv); for(int i=1;i<=n;i++){ //前缀和 if(w[i]>=W)sn[i]=sn[i-1]+1,sv[i]=sv[i-1]+v[i]; else sn[i]=sn[i-1],sv[i]=sv[i-1]; } LL y=0; for(int i=1;i<=m;i++) y+=(sn[r[i]]-sn[l[i]-1])*(sv[r[i]]-sv[l[i]-1]); ans=min(ans,llabs(y-s)); //最优解 return y<=s; //W大,y小 } LL find(){ int l=0,r=1e6+1; while(l+1<r){ int mid=l+r>>1; if(check(mid)) r=mid; //最小化 else l=mid; } return ans; } int main(){ scanf("%d %d %lld",&n,&m,&s); for(int i=1;i<=n;i++) scanf("%d%d",&w[i],&v[i]); for(int i=1;i<=m;i++) scanf("%d%d",&l[i],&r[i]); printf("%lld",find()); return 0; }
4. Luogu P1083 [NOIP2012 提高组] 借教室
#include<iostream> #include<cstring> #include<cstdio> using namespace std; const int N = 1000010; int n,m; int r[N],d[N],s[N],t[N]; long long num[N]; //每天教室需求数 bool check(int x){ memset(num,0,sizeof num); for(int i=1;i<=x;i++){//枚举订单数 num[s[i]]+=d[i]; num[t[i]+1]-=d[i]; //差分 } for(int i=1;i<=n;i++){//枚举天数 num[i]+=num[i-1]; //前缀和 if(num[i]>r[i])return false; } return true; //x小,true } int find(){ int l=0,r=m+1; while(l+1<r){ int mid=l+r>>1; if(check(mid)) l=mid; //最大化 else r=mid; } return l; } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",&r[i]); for(int i=1;i<=m;i++) scanf("%d%d%d",&d[i],&s[i],&t[i]); if(check(m)){puts("0");return 0;} printf("-1\n%d",find()+1);//匹配失败的订单 return 0; }
#include <iostream> #include <cstring> #include <algorithm> using namespace std; const int N=1005; int dx[]={-1,0,1,0},dy[]={0,1,0,-1}; int n,m,p[N][N]; bool vis[N][N]; bool dfs(int x,int y,int P){ if(x==n) return true; vis[x][y]=true; for(int i=0; i<4; ++i){ int a=x+dx[i],b=y+dy[i]; if(a>=1&&a<=n&&b>=1&&b<=m &&!vis[a][b]&&p[a][b]<=P) if(dfs(a,b,P))return true; } //P大,易true return false; } int find(){ int l=-1,r=1001; while(l+1<r){ int mid=l+r>>1; memset(vis,0,sizeof vis); if(dfs(1,1,mid)) r=mid; //最小化 else l=mid; } return r; } int main(){ scanf("%d%d",&n,&m); for(int i=1; i<=n; i++) for(int j=1; j<=m; j++) scanf("%d",&p[i][j]); printf("%d",find()); return 0; }
#include <iostream> #include <cstring> #include <algorithm> using namespace std; int a,b,c; bool check(double x){ double s=a; //s为未还的钱数 for(int i=1;i<=c;i++) s=s*(1+x)-b; return s>=0; //x大,s大 } double find(){ double l=0, r=10; while(r-l>1e-5){ double mid=(l+r)/2; if(check(mid)) r=mid; //最小化 else l=mid; } return r; } int main(){ scanf("%d%d%d",&a,&b,&c); printf("%.1lf",find()*100); return 0; }
7. Luogu P1873 [COCI 2011/2012 #5] EKO / 砍树
#include <iostream> #include <cstring> #include <algorithm> using namespace std; typedef long long LL; int n,M,h[1000010]; bool check(int x){ LL s=0; for(int i=1;i<=n;i++) if(h[i]>x) s+=h[i]-x; return s>=M; //x小,s大 } int find(){ int l=0,r=1e9; while(l+1<r){ int mid=l+r>>1; if(check(mid)) l=mid; else r=mid; } return l; } int main(){ scanf("%d%d",&n,&M); for(int i=1;i<=n;i++)scanf("%d",&h[i]); printf("%d",find()); return 0; }
#include <iostream> #include <cstring> #include <algorithm> using namespace std; const int N = 10005; int n, k, a[N]; bool check(int x){ int cnt=0; for(int i=1;i<=n;i++)cnt+=a[i]/x; return cnt>=k; //X小,cnt大 } int find(){ int l=0, r=1e7+1; while(l+1<r){ int mid=l+r>>1; if(check(mid)) l=mid; else r=mid; } return l; } int main(){ cin >> n >> k; double x; for(int i=1; i<=n; i++) cin>>x,a[i]=int(x*100);//转化 printf("%.2f",find()/100.0); return 0; }
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int n,C,a[100010]; bool check(int x){ int last=0,cnt=1; for(int i=1;i<n;i++) if(a[i]-a[last]>=x) last=i,cnt++; return cnt>=C; //x小,cnt大 } int find(){ int l=0,r=1e9+1; while(l+1<r){ int mid=l+r>>1; if(check(mid)) l=mid; else r=mid; } return l; } int main(){ scanf("%d%d",&n,&C); for(int i=0;i<n;i++) scanf("%d",&a[i]); sort(a,a+n); printf("%d",find()); return 0; }
10. Luogu P1182 数列分段 Section II
#include<cstdio> #include<iostream> #include<algorithm> using namespace std; int n,m,mx,a[100010]; bool check(int mid){ int sum=0,cnt=1; for(int i=1;i<=n;i++){ if(sum+a[i]<=mid)sum+=a[i]; //贪心 else sum=a[i],cnt++; //新开一段 } return cnt<=m; } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); mx=max(mx,a[i]); } int l=mx-1,r=1e9+1; //注意l不能=0 while(l+1<r){ int mid=(l+r)>>1; if(check(mid)) r=mid; else l=mid; } printf("%d\n",r); return 0; } /* l=mx-1的问题: 3 3 2 4 5 T:5 F:2 */
练习题
Luogu P2824 [HEOI2016/TJOI2016]排序
Luogu P5021 [NOIP2018 提高组] 赛道修建
Luogu P1084 [NOIP2012 提高组] 疫情控制