1047: [HAOI2007]理想的正方形
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 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
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);
}