题目大意: 给出一个矩阵,找出里面最大值与最小值的差值最小的 n × n n \times n n×n 大小的矩阵。
题解
首先考虑暴力,枚举每个 n × n n \times n n×n 的矩阵,时间复杂度 O ( a × b × n 2 ) O(a \times b \times n^2) O(a×b×n2)。
显然我们只能承受 O ( a × b ) O(a \times b) O(a×b) 的时间复杂度,于是考虑优化掉那个 n 2 n^2 n2 的部分。
发现我们可以预处理两个数组: m a [ i ] [ j ] ma[i][j] ma[i][j] 和 m i [ i ] [ j ] mi[i][j] mi[i][j],分别表示第 i i i 行从第 j j j 个开始往前的 n n n 个数字中的最大值和最小值。这个只需要用单调队列扫一遍就可以了。
发现预处理完这个东西之后可以利用它竖着跑单调队列,每次加进来的 n n n 中的最大最小值我们已经知道了,只需要 O ( 1 ) O(1) O(1) 读取即可,然后顺便更新一下答案就可以了。
代码如下:
#include <cstdio>
#define maxn 1010
int a,b,n;
int ma[maxn][maxn],mi[maxn][maxn];
struct queue_{
int q[maxn],time[maxn],st,ed;
void reset(){st=1;ed=0;}
}q1,q2;
int min(int x,int y){return x<y?x:y;}
int main()
{
scanf("%d %d %d",&a,&b,&n);
for(int i=1;i<=a;i++)
{
q1.reset();q2.reset();
for(int j=1;j<=b;j++)
{
int x; scanf("%d",&x);
while(q1.ed>=q1.st&&q1.q[q1.ed]<x)q1.ed--; while(q1.st<=q1.ed&&q1.time[q1.st]<j-n+1)q1.st++;
q1.q[++q1.ed]=x; q1.time[q1.ed]=j;
while(q2.ed>=q2.st&&q2.q[q2.ed]>x)q2.ed--; while(q2.st<=q2.ed&&q2.time[q2.st]<j-n+1)q2.st++;
q2.q[++q2.ed]=x; q2.time[q2.ed]=j;
ma[i][j]=q1.q[q1.st],mi[i][j]=q2.q[q2.st];
}
}
int ans=2147483640;
for(int j=n;j<=b;j++)
{
q1.reset();q2.reset();
for(int i=1;i<=a;i++)
{
while(q1.ed>=q1.st&&q1.q[q1.ed]<ma[i][j])q1.ed--; while(q1.st<=q1.ed&&q1.time[q1.st]<i-n+1)q1.st++;
q1.q[++q1.ed]=ma[i][j]; q1.time[q1.ed]=i;
while(q2.ed>=q2.st&&q2.q[q2.ed]>mi[i][j])q2.ed--; while(q2.st<=q2.ed&&q2.time[q2.st]<i-n+1)q2.st++;
q2.q[++q2.ed]=mi[i][j]; q2.time[q2.ed]=i;
if(i>=n&&q1.q[q1.st]-q2.q[q2.st]<ans)ans=q1.q[q1.st]-q2.q[q2.st];
}
}
printf("%d",ans);
}