您的位置:首页 > 其它

洛谷10月月赛R2·浴谷八连测R3 P3933 Chtholly Nota Seniorious

2017-10-28 08:17 387 查看
这个题可以用二分,然后贪心

其实一开始也有想到,不过不知道怎么贪,看了题解恍然大悟

当最大值再四个角的区域是不同的,所以要从四个角开始找,然后是成阶梯状的,下一层一定小于等于上一层,如果最大值在这个区域,最大指减每一个都要比答案小,同理最小值在某个区域,每个值减最小值都所比答案小,然后检验另一个区域就行了,所以一行行的贪就可以

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>

#define ll long long
using namespace std;

int n,m,a[5][2200][2200],last[2100],maxn,minn=199999999;
bool ch(int x,int opt){
if(opt&1) swap(n,m);//奇数时是横过来了
last[0]=m;
for(int i=1;i<=n;i++){
int j;
for( j=1;j<=last[i-1];j++)
if(maxn-a[opt][i][j]>x) break;
last[i]=j-1;
}//贪心
for(int i=1;i<=n;i++){
int j;
for( j=last[i]+1;j<=m;j++)
if(a[opt][i][j]-minn>x) {
if(opt&1) swap(n,m);return 0;
}
}//检验

if(opt&1) swap(n,m);
return 1;
}
bool check(int x){
return ch(x,0)||ch(x,1)||ch(x,2)||ch(x,3);//四个角取交集
}
int main(){

scanf("%d%d",&n,&m);
int x2=n,x3=m,x=1,y=n,y2=m,y3=1;
for (int i=1;i<=n;i++){

for (int j = 1; j <= m; j++){
scanf("%d",&a[0][i][j]);
a[1][x++][y]=a[2][x2][y2--]=a[3][x3--][y3]=a[0][i][j];
if (a[0][i][j]>maxn) maxn=a[0][i][j];
if (a[0][i][j]<minn) minn=a[0][i][j];
}
y--; x=1;
x2--; y2=m;
y3++; x3=m;  } //输入四个角
int l=0,r=maxn-minn;
while(l<=r){
int mid=(l+r)>>1;
int w=check(mid);
if(w) r=mid-1;
else l=mid+1;//二分答案
}
printf("%d",l);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: