bzoj 1047
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
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
用单调队列求出mapp[i][j]第i行第j列同行前n个中的最小值和最大值,接着用相同的思想对同列处理(其实相当于把mapp[i][j](j>=n)更新为mapp[i][j-n]到mapp[i][j]的最值)
对列处理的时候一定要注意i,j均>=n !!!!!
#include<cstdio>
#include<iostream>
#include<queue>
#include<cstring>
#define M 1010
#define t1 qmin[tail1]
#define t2 qmax[tail2]
#define h1 qmin[head1]
#define h2 qmax[head2]
#define FOR(a,b) for(int a=1;a<=b;a++)
using namespace std;
struct Num{
int x,y;
}qmin[M],qmax[M],minn,maxn;
int mapp[M][M],head1,head2,tail1,tail2,lmin[M][M],lmax[M][M],a,b,n,ans;
void ins(int x,int y)
{
while(head1<=tail1&&mapp[t1.x][t1.y]>mapp[x][y])
tail1--;
tail1++;
t1.x=x,t1.y=y;
while(head2<=tail2&&mapp[t2.x][t2.y]<mapp[x][y])
tail2--;
tail2++;
t2.x=x,t2.y=y;
}
void get(int x,int y)
{
while(head1<=tail1&&y-h1.y>=n)
head1++;
minn=h1;
while(head2<=tail2&&y-h2.y>=n)
head2++;
maxn=h2;
}
void ins1(int x,int y)
{
while(head1<=tail1&&lmin[t1.x][t1.y]>lmin[x][y])
tail1--;
tail1++;
t1.x=x,t1.y=y;
while(head2<=tail2&&lmax[t2.x][t2.y]<lmax[x][y])
tail2--;
tail2++;
t2.x=x,t2.y=y;
}
void get1(int x,int y)
{
while(head1<=tail1&&x-h1.x>=n)
head1++;
minn=h1;
while(head2<=tail2&&x-h2.x>=n)
head2++;
maxn=h2;
}
int main()
{
scanf("%d%d%d",&a,&b,&n);
FOR(i,a)
FOR(j,b)
{
scanf("%d",&mapp[i][j]);
}
FOR(i,a)
{
head1=head2=1,tail1=tail2=0;
FOR(j,b)
{
ins(i,j);get(i,j);
lmin[i][j]=mapp[minn.x][minn.y];
lmax[i][j]=mapp[maxn.x][maxn.y];
}
}
ans=1000000000;
for(int j=1;j<=b;j++)
{
head1=head2=1,tail1=tail2=0;
for(int i=1;i<=a;i++)
{
ins1(i,j);
get1(i,j);
if(i>=n&&j>=n)
ans=min(ans,lmax[maxn.x][maxn.y]-lmin[minn.x][minn.y]);
}
}
printf("%d\n",ans);
return 0;
}