bzoj1047【haoi2007】理想正方形

1047: [HAOI2007]理想的正方形

Time Limit: 10 Sec   Memory Limit: 162 MB
Submit: 2151   Solved: 1146
[ Submit][ Status][ Discuss]

Description

有一个a*b的整数组成的矩阵,现请你从中找出一个n*n的正方形区域,使得该区域所有数中的最大值和最小值的差最小。

Input

第一行为3个整数,分别表示a,b,n的值第二行至第a+1行每行为b个非负整数,表示矩阵中相应位置上的数。每行相邻两数之间用一空格分隔。

Output

仅一个整数,为a*b矩阵中所有“n*n正方形区域中的最大整数和最小整数的差值”的最小值。

Sample Input

5 4 2
1 2 5 6
0 17 16 0
16 17 2 1
2 10 2 1
1 2 2 2

Sample Output

1

HINT

问题规模

(1)矩阵中的所有数都不超过1,000,000,000

(2)20%的数据2<=a,b<=100,n<=a,n<=b,n<=10

(3)100%的数据2<=a,b<=1000,n<=a,n<=b,n<=100

Source




令f[i][j]=max(w[i][j-n+1],w[i][j-n+2],…,w[i][j]),g[i][j]=max(w[i-n+1][j],w[i-n+2][j],…,w[i][j])。那么g[i][j]即为以(i,j)为左下角点的n*n区域中最大值。同理,可求得n*n区域中最小值。

在求f[i][j]和g[i][j]时可用单调队列



#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define F(i,j,n) for(int i=j;i<=n;i++)
#define D(i,j,n) for(int i=j;i>=n;i--)
#define LL long long
using namespace std;
int n,a,b,l1,l2,r1,r2,ans;
int w[1005][1005],f[1005][1005][2],g[1005][1005][2],p[1005][2],q[1005][2];
int main()
{
//	freopen("input.in","r",stdin);
//	freopen("output.out","w",stdout);
	scanf("%d%d%d",&a,&b,&n);
	F(i,1,a) F(j,1,b) scanf("%d",&w[i][j]);
	F(i,1,a) 
	{
		l1=l2=1;
		r1=r2=0;
		F(j,1,n-1)
		{
			while (p[r1][0]<=w[i][j]&&r1>=l1) r1--;
			p[++r1][0]=w[i][j];
			p[r1][1]=j;
			while (q[r2][0]>=w[i][j]&&r2>=l2) r2--;
			q[++r2][0]=w[i][j];
			q[r2][1]=j;
		}
		F(j,n,b)
		{
			while (p[r1][0]<=w[i][j]&&r1>=l1) r1--;
			p[++r1][0]=w[i][j];
			p[r1][1]=j;
			while (p[l1][1]<j-n+1) l1++;
			f[i][j][0]=p[l1][0];
			while (q[r2][0]>=w[i][j]&&r2>=l2) r2--;
			q[++r2][0]=w[i][j];
			q[r2][1]=j;
			while (q[l2][1]<j-n+1) l2++;
			f[i][j][1]=q[l2][0];
		}
	}
	F(j,n,b)
	{
		l1=l2=1;
		r1=r2=0;
		F(i,1,n-1)
		{
			while (p[r1][0]<=f[i][j][0]&&r1>=l1) r1--;
			p[++r1][0]=f[i][j][0];
			p[r1][1]=i;
			while (q[r2][0]>=f[i][j][1]&&r2>=l2) r2--;
			q[++r2][0]=f[i][j][1];
			q[r2][1]=i;
		}
		F(i,n,a)
		{
			while (p[r1][0]<=f[i][j][0]&&r1>=l1) r1--;
			p[++r1][0]=f[i][j][0];
			p[r1][1]=i;
			while (p[l1][1]<i-n+1) l1++;
			g[i][j][0]=p[l1][0];
			while (q[r2][0]>=f[i][j][1]&&r2>=l2) r2--;
			q[++r2][0]=f[i][j][1];
			q[r2][1]=i;
			while (q[l2][1]<i-n+1) l2++;
			g[i][j][1]=q[l2][0];
		}
	}
	ans=2000000000;
	F(i,n,a) F(j,n,b) ans=min(ans,g[i][j][0]-g[i][j][1]);
	printf("%d\n",ans);
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值