题目描述
有一个a*b的整数组成的矩阵,现请你从中找出一个n*n的正方形区域,使得该区域所有数中的最大值和最小值的差最小。
输入输出格式
输入格式:第一行为3个整数,分别表示a,b,n的值
第二行至第a+1行每行为b个非负整数,表示矩阵中相应位置上的数。每行相邻两数之间用一空格分隔。
输出格式:仅一个整数,为a*b矩阵中所有“n*n正方形区域中的最大整数和最小整数的差值”的最小值。
输入输出样例
输入样例#1:
5 4 2 1 2 5 6 0 17 16 0 16 17 2 1 2 10 2 1 1 2 2 2
输出样例#1:
1
说明
问题规模
(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
暴力扫描是O(a*b*n*n)的复杂度一定是不行的。
开两个单调队列,一个维护列的最大最小值,一个维护方形区域。
#include<algorithm>
#include<iostream>
#include<cstdio>
using namespace std;
int a,b,n,ans=1e9+7,f[1005][1005],qmin[1005],qmax[1005],hmxans[1005][1005],hmnans[1005][1005],gmnans[1005][1005],gmxans[1005][1005];
int main()
{
scanf("%d%d%d",&a,&b,&n);
for(int i=1;i<=a;i++)
for(int j=1;j<=b;j++)
scanf("%d",&f[i][j]);
for(int i=1;i<=a;i++)
{
int h_min=1,h_max=1,t_min=0,t_max=0;
for(int j=1;j<=b;j++)
{
while(h_min<=t_min&&f[i][qmin[t_min]]>f[i][j])
t_min--;
qmin[++t_min]=j;
while(h_min<=t_min&&qmin[t_min]-qmin[h_min]>=n)
h_min++;
hmnans[i][max(1,j-n+1)]=f[i][qmin[h_min]];
while(h_max<=t_max&&f[i][qmax[t_max]]<f[i][j])
t_max--;
qmax[++t_max]=j;
while(h_max<=t_max&&qmax[t_max]-qmax[h_max]>=n)
h_max++;
hmxans[i][max(1,j-n+1)]=f[i][qmax[h_max]];
}
}
for(int i=1;i<=b;i++)
{
int h_min=1,h_max=1,t_min=0,t_max=0;
for(int j=1;j<=a;j++)
{
while(h_min<=t_min&&hmnans[qmin[t_min]][i]>hmnans[j][i])
t_min--;
qmin[++t_min]=j;
while(h_min<=t_min&&qmin[t_min]-qmin[h_min]>=n)
h_min++;
gmnans[max(1,j-n+1)][i]=hmnans[qmin[h_min]][i];
while(h_max<=t_max&&hmxans[qmax[t_max]][i]<hmxans[j][i])
t_max--;
qmax[++t_max]=j;
while(h_max<=t_max&&qmax[t_max]-qmax[h_max]>=n)
h_max++;
gmxans[max(1,j-n+1)][i]=hmxans[qmax[h_max]][i];
}
}
for(int i=1;i<=a-n+1;i++)
for(int j=1;j<=b-n+1;j++)
ans=min(ans,gmxans[i][j]-gmnans[i][j]);
printf("%d\n",ans);
return 0;
}