矩阵分组
描述
有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,2 | n<=10,m<=10 |
3-4 | n=1,m<=2000 |
5-7 | n<=200,m<=200 |
8-10 | n<=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;
}