A06 二分答案

A06 二分答案 最好的套路_哔哩哔哩_bilibili

 

1. Luogu P2440 木材加工

#include<bits/stdc++.h>
using namespace std;

const int N=100005;
int n,k,a[N];

bool check(int x){
  long long cnt=0; //段数
  for(int i=1;i<=n;i++) cnt+=a[i]/x;
  return cnt>=k;
}
int main(){
  scanf("%d%d",&n,&k);
  for(int i=1; i<=n; i++)scanf("%d",&a[i]);
  
  int l=0, r=1e8+1;
  while(l+1<r){
    int mid=l+r>>1;
    if(check(mid)) l=mid; //最大化
    else r=mid;
  }  
  printf("%d\n",l);
  return 0;
}

 

2. Luogu P2678 [NOIP2015 提高组] 跳石头

#include<bits/stdc++.h>
using namespace std;

int L,n,m,a[500005];

bool check(int x){
  int last=0,cnt=0;
  for(int i=1;i<=n;i++)
    if(a[i]-a[last]<x) cnt++;//贪心
    else last=i; 
  return cnt<=m;
}
int main(){
  scanf("%d%d%d",&L,&n,&m);
  for(int i=1;i<=n;i++)scanf("%d",&a[i]);
  a[++n]=L; //右边界
  
  int l=0,r=1e9+1;
  while(l+1<r){
    int mid=l+r>>1;
    if(check(mid)) l=mid; //最大化
    else r=mid;
  }  
  printf("%d\n",l);
  return 0;
}

 

3. Luogu P1314 [NOIP2011 提高组] 聪明的质监员

#include<bits/stdc++.h>
using namespace std;

const int N=200010;
int n,m,w[N],v[N],l[N],r[N];
long long s,sn[N],sv[N],ans=1e18;

bool check(int x){
  memset(sn,0,sizeof sn);
  memset(sv,0,sizeof sv);
  for(int i=1;i<=n;i++){ //前缀和
    if(w[i]>=x)sn[i]=sn[i-1]+1,sv[i]=sv[i-1]+v[i];
    else sn[i]=sn[i-1],sv[i]=sv[i-1];
  }
  long long 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;
}
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]);
    
  int l=0,r=1e6+1;
  while(l+1<r){
    int mid=l+r>>1;
    if(check(mid)) r=mid; //最小化
    else l=mid;
  }
  printf("%lld",ans);
  return 0;
}

 

4. Luogu P1083 [NOIP2012 提高组] 借教室

#include<bits/stdc++.h>
using namespace std;

const int N=1000010;
int n,m,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;
}
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;} 

  int l=0,r=m+1;
  while(l+1<r){
    int mid=l+r>>1;
    if(check(mid)) l=mid; //最大化
    else r=mid;
  }  
  printf("-1\n%d",l+1); //匹配失败的订单
  return 0;
}

 

5. Luogu P1902 刺杀大使

#include<bits/stdc++.h>
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;
  }
  return false;
}
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]); 

  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;
  }      
  printf("%d",r);
  return 0;
}

 

6. Luogu P1163 银行贷款

#include<bits/stdc++.h>
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;
}
int main(){
  scanf("%d%d%d",&a,&b,&c);
  
  double l=0, r=10;
  while(r-l>1e-5){
    double mid=(l+r)/2;
    if(check(mid)) r=mid; //最小化
    else l=mid;
  }
  printf("%.1lf",r*100);
  return 0;
}

 

7. Luogu P1873 [COCI 2011/2012 #5] EKO / 砍树

#include<bits/stdc++.h>
using namespace std;

int n,M,h[1000010];

bool check(int x){
  long long s=0;
  for(int i=1;i<=n;i++)
    if(h[i]>x) s+=h[i]-x;
  return s>=M;
}
int main(){
  scanf("%d%d",&n,&M);
  for(int i=1;i<=n;i++)scanf("%d",&h[i]);
  
  int l=0,r=1e9;
  while(l+1<r){
    int mid=l+r>>1;
    if(check(mid)) l=mid;
    else r=mid;
  }  
  printf("%d",l);
  return 0;
}

 

8. Luogu P1577 切绳子

#include<bits/stdc++.h>
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;
}
int main(){
  cin >> n >> k;
  double x;
  for(int i=1; i<=n; i++) 
    cin>>x,a[i]=int(x*100);//转化

  int l=0,r=1e7+1;
  while(l+1<r){
    int mid=l+r>>1;
    if(check(mid)) l=mid;
    else r=mid;
  }    
  printf("%.2f",l/100.0);
  return 0;
}

 

9. Luogu P1824 进击的奶牛

#include<bits/stdc++.h>
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;
}
int main(){ 
  scanf("%d%d",&n,&C);
  for(int i=0;i<n;i++)scanf("%d",&a[i]);
  sort(a,a+n);
  
  int l=0,r=1e9+1;
  while(l+1<r){
    int mid=l+r>>1;
    if(check(mid)) l=mid;
    else r=mid;
  }  
  printf("%d",l);
  return 0;
}

 

10. Luogu P1182 数列分段 Section II

#include<bits/stdc++.h>
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 P1404 平均数

Luogu P7333 [JRKSJ R1] JFCA

Luogu P8088 『JROI-5』Autumn

Luogu P2824 [HEOI2016/TJOI2016]排序

CF1486D Max Median

Luogu P5021 [NOIP2018 提高组] 赛道修建

Luogu P1084 [NOIP2012 提高组] 疫情控制

 

POJ3104 Drying

POJ3273 Monthly Expense

POJ2456 Aggressive cows

POJ2110 Mountain Walking

 POJ1905 Expanding Rods

POJ3111 K Best

POJ2018 Best Cow Fences

 

posted @ 2023-01-31 17:20  董晓  阅读(3067)  评论(3)    收藏  举报