【NOIP模拟】矩阵分组

                                               矩阵分组 

描述

有N行M列的矩阵,每个格子中有一个数字,现在需要你将格子的数字分为A,B两部分

要求:

1、每个数字恰好属于两部分的其中一个部分

2、每个部分内部方块之间,可以上下左右相互到达,且每个内部方块之间可以相互到达,且最多拐一次弯

如:

AAAAA  AAAAA  AAAAA
AABAA  BaAAA  AAABB
ABBBA  BBAAA  AAABB
AABAA  BaAAA  ABBBB
AAAAA  AAAAA  BBBBB

  (1)     (2)     (3) 

其中(1)(2)是不允许的分法,(3)是允许的分法。在(2)中,a属于A区域,这两个a元素之间互相到达,但是不满足只拐一次弯到达。

问:对于所有合法的分组中,A区域和B区域的极差,其中极差较大的一个区域最小值是多少

提示:极差就是区域内最大值减去最小值。

输入

第一行两个正整数n,m

接下来n 行,每行m个自然数A_{i,j}表示权值

输出

输出一行表示答案

样例输入

4 4
1 12 6 11
11 4 2 14
10 1 9 20
4 17 13 10

样例输出

11

提示

【样例解释】 1 12 6 11 11 4 2 14 10 1 9 20 4 17 13 10

分法不唯一,如图是一种合法的分法。左边部分极差12-1=11,右边一块极差20-10=10,所以答案取这两个中较大者11。没有别的分法,可以使答案更小。

测试点N,m范围
1,2n<=10,m<=10
3-4n=1,m<=2000
5-7n<=200,m<=200
8-10n<=2000,m<=2000

所有权值1<=a_ij<=10^9

 

代码:
 

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
using namespace std;

const int Max=2005;
int n,m,maxx=-1e9,minn=1e9,l,r,mid;
int num[4][Max][Max],end[Max];

inline int get_int()
{
	int x=0;
	char c;
	for(c=getchar();(!isdigit(c));c=getchar());
	for(;isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+(c^48);
	return x;
}

inline int mx(int x,int y){return x<y?y:x;}
inline int mn(int x,int y){return x<y?x:y;}
inline void swap(int&x,int&y){x^=y,y^=x,x^=y;}
inline bool check(int id,int mid)
{
	if(id&1) swap(n,m);
	end[0]=1;
	for(int j=1,i;j<=m;++j)
	{
	  for(i=n;i>=end[j-1];--i)
	  	if(maxx-num[id][i][j]>mid) break;
	  end[j]=i+1;
	}
	for(int j=1;j<=m;++j)
	  for(int i=end[j]-1;i>=1;--i)
	  	if(num[id][i][j]-minn>mid) {if(id&1) swap(n,m);return 0;}
	if(id&1) swap(n,m);
	return 1;
}

inline bool calc(int mid)
{
	return(check(0,mid)||check(1,mid)||check(2,mid)||check(3,mid));
}

inline void solve()
{
	l=0,r=maxx-minn;
	while(l<r)
	{
	  mid=(l+r)>>1;
	  if(calc(mid)) r=mid;
	  else l=mid+1;
	}
}

int main()
{
	n=get_int(),m=get_int();
	int x1=1,y1=1,x2=m,y2=1,x3=n,y3=m,x4=1,y4=n;
	for(int i=1;i<=n;++i)
	{
	  for(int j=1;j<=m;++j)
	  {
	  	int x=get_int();
	  	num[0][x1][y1++]=num[1][x2--][y2]=num[2][x3][y3--]=num[3][x4++][y4]=x;
	  	maxx=mx(maxx,x),minn=mn(minn,x);
	  }
	  x1++,y1=1,x2=m,y2++,x3--,y3=n,x4=1,y4--;
	}
	solve();
	cout<<r<<"\n";
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值