洛谷3933 Chtholly Nota Seniorious 二分答案+贪心

时间:2023-03-09 04:26:26
洛谷3933 Chtholly Nota Seniorious  二分答案+贪心

题目链接

题意

给你一个N*M的矩阵 (N,M <=2000)  把他分成两部分 使两部分的极差较大的一个最小  求这个最小值。然后分矩阵的要求是:每个部分内部的方块之间,可以通过上下左右相互到达,而且每个内部的方块之间互相到达,最多允许拐一次弯(不能出现“凹”233)

二分答案+贪心

二分上界是矩阵max-min

判断的时候 由于 分开的矩阵在每一行肯定是连续的 所以就按顺序扫一遍 判断一下在哪里分开即可

还有就是由于最大值最小值所在的位置不确定 ,我们需要旋转3次这个矩阵然后求最优答案

代码

#include<bits/stdc++.h>
#define MAXN 2017
#define INF 0x7f7f7f7f
using namespace std;
int N,M,a[MAXN][MAXN],maxa,mina=INF,ans=INF;
bool check(int tmp){
int pos=;
for(int i=;i<=N;i++)
{
for(int j=;j<=M;j++)
if(a[i][j]<maxa-tmp)
pos=max(j+,pos);
for(int j=;j<=M;j++)
if(a[i][j]>mina+tmp)
if(j<pos)return ;
}
return ;
}
int Solve(){
int l=,r=maxa-mina;
while(l<r){
int mid=l+r>>;
if(check(mid))r=mid;
else l=mid+;
}
return l;
}
void flip1(){
for(int i=;i<=N/;i++)
for(int j=;j<=M;j++)
swap(a[i][j],a[N-i+][j]);
}
void flip2(){
for(int j=;j<=M/;j++)
for(int i=;i<=N;i++)
swap(a[i][j],a[i][M-j+]);
} int main()
{
scanf("%d%d",&N,&M);
for(int i=;i<=N;i++)
for(int j=;j<=M;j++){
scanf("%d",&a[i][j]);
maxa=max(maxa,a[i][j]);mina=min(mina,a[i][j]);
}
flip2();
ans=Solve();
flip1();ans=min(ans,Solve());
flip2();ans=min(ans,Solve());
flip2();ans=min(ans,Solve());
printf("%d\n",ans);
return ;
}