康复训练之二分

前言:AFO了一年,重新备战CSP&NOIP,故进行简单的恢复训练,以便能够快速到达TG省二水平

今天回顾的是二分。

何时使用二分?

对一个满足单调性质的问题,如:“使最大值最小”或“使最小值最大”等时,我们可以采用二分答案的方法来解决。

二分模板是什么?


l=-1,r=N;
while(l+1!=r){
    m=(l+r)/2;
    if(pd(m)) l=m;
    else r=m;
}
return l or r(根据题意来看);

此模板包含所有类型,妈妈再也不用担心我边界值搞不清了hhhhh

简单例题选讲

T1:[NOIP2015 提高组] 跳石头

二分答案,判断此答案是否在移除 \(M\) 块之内可行。

Code:

#include<bits/stdc++.h>
using namespace std;
#define FOR(i,a,b) for(int i=a;i<=b;i++)
#define REP(i,a,b) for(int i=a;i>=b;i--)
inline int read(){
    int sum=0,ff=1; char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-') ff=-1;
        ch=getchar();
    }
    while(isdigit(ch))
        sum=sum*10+(ch^48),ch=getchar();
    return sum*ff;
}
inline void write(int x){
    if(x==0){
        putchar('0');
        return ;
    }
    char F[200];
    int tmp=x>0?x:-x,cnt=0;
    if(x<0) putchar('-');
    while(tmp>0)
        F[cnt++]=tmp%10+'0',tmp/=10;
    while(cnt>0) putchar(F[--cnt]);
}
int a[50005],b[50005],L,N,M;
bool pd(int x){
    int sum=0;
    FOR(i,1,N+1) b[i]=a[i];
    FOR(i,1,N+1) if(b[i]-b[i-1]<x) sum++,b[i]=b[i-1];
    if(sum<=M) return 1;
    else return 0;
}
int main(){
    L=read(),N=read(),M=read();
    if(N==0&&M==0){
        write(L);
        return 0;
    }
    FOR(i,1,N) a[i]=read();
    a[N+1]=L;
    int l=-1,r=L;
    while(l+1!=r){
        int mid=(l+r)/2;
        if(pd(mid)) l=mid;
        else r=mid;
    }
    write(l);
    return 0;
}

T2:刺杀大使

简单理解下,发现就是求一条路径上的最大值最小。

二分套一个 \(B/DFS\) 即可。

Code:




#include<bits/stdc++.h>
using namespace std;
const int N=1005;
#define FOR(i,a,b) for(int i=a;i<=b;i++)
#define REP(i,a,b) for(int i=a;i>=b;i--)
inline int read(){
    int sum=0,ff=1; char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-') ff=-1;
        ch=getchar();
    }
    while(isdigit(ch))
        sum=sum*10+(ch^48),ch=getchar();
    return sum*ff;
}
inline void write(int x){
    if(x==0){
        putchar('0');
        return ;
    }
    char F[200];
    int tmp=x>0?x:-x,cnt=0;
    if(x<0) putchar('-');
    while(tmp>0)
        F[cnt++]=tmp%10+'0',tmp/=10;
    while(cnt>0) putchar(F[--cnt]);
}
int n,m,p[N][N];
const int dx[]={0,1,0,-1,0};
const int dy[]={0,0,1,0,-1};
bool vis[N][N];
queue<int>x;
queue<int>y;
bool pd(int sum){
    memset(vis,0,sizeof vis);
    while(!x.empty()) x.pop(),y.pop();
    vis[1][1]=1;
    x.push(1);
    y.push(1);
    while(!x.empty()){
        int xx=x.front();
        int yy=y.front();
        x.pop();y.pop();
        FOR(i,1,4){
            int X=xx+dx[i],Y=yy+dy[i];
            if(X<1||Y<1||X>n||Y>m||vis[X][Y]||p[X][Y]>sum) continue;
            vis[X][Y]=1;
            if(X==n) return 0;
            x.push(X);
            y.push(Y);
        }
    }
    return 1;
}
int main(){
    int l=0,r=0;
    n=read(),m=read();
    FOR(i,1,n) FOR(j,1,m) p[i][j]=read(),r=max(r,p[i][j]);
    while(l+1!=r){
        int mid=(l+r)/2;
        if(pd(mid)) l=mid;
        else r=mid;
    }
    write(r);
    return 0;
}

由于时间关系,二分暂时复习到这里,接下去还会是不是地更新其他内容,敬请期待。

posted @ 2021-09-05 16:13  沸-腾-鱼  阅读(65)  评论(0编辑  收藏  举报