前言: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;
}
由于时间关系,二分暂时复习到这里,接下去还会是不是地更新其他内容,敬请期待。