题目描述
有一个a*b的整数组成的矩阵,现请你从中找出一个n*n的正方形区域,使得该区域所有数中的最大值和最小值的差最小。
【题目分析】
单调队列优化DP
【代码】
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
int dpmx[1001][1001];
int dpmi[1001][1001];
int dp2mx[1001][1001];
int dp2mi[1001][1001];
int a[1001][1001];
int n,m,k;
int que[1001],hd=1,tl=0,ans=0x3f3f3f3f;
int main()
{
scanf("%d%d%d",&n,&m,&k);
for (int i=1;i<=n;++i)
for (int j=1;j<=m;++j)
scanf("%d",&a[i][j]);
for (int i=1;i<=n;++i)
{
for (int j=1;j<=m;++j) dpmx[i][j]=dpmi[i][j]=a[i][j];
hd=1;tl=0;
for (int j=1;j<=m;++j)
{
while (hd<=tl&&j-que[hd]>=k) hd++;
while (hd<=tl&&a[i][que[tl]]<=a[i][j]) tl--;
que[++tl]=j;
dpmx[i][j]=a[i][que[hd]];
}
hd=1;tl=0;
for (int j=1;j<=m;++j)
{
while (hd<=tl&&j-que[hd]>=k) hd++;
while (hd<=tl&&a[i][que[tl]]>=a[i][j]) tl--;
que[++tl]=j;
dpmi[i][j]=a[i][que[hd]];
}
}
for (int j=1;j<=m;++j)
{
hd=1;tl=0;
for (int i=1;i<=n;++i)
{
while (hd<=tl&&i-que[hd]>=k) hd++;
while (hd<=tl&&dpmx[que[tl]][j]<=dpmx[i][j]) tl--;
que[++tl]=i;
dp2mx[i][j]=dpmx[que[hd]][j];
}
hd=1;tl=0;
for (int i=1;i<=n;++i)
{
while (hd<=tl&&i-que[hd]>=k) hd++;
while (hd<=tl&&dpmi[que[tl]][j]>=dpmi[i][j]) tl--;
que[++tl]=i;
dp2mi[i][j]=dpmi[que[hd]][j];
}
}
for (int i=k;i<=n;++i)
for (int j=k;j<=m;++j)
ans=min(ans,dp2mx[i][j]-dp2mi[i][j]);
printf("%d\n",ans);
}