给出一个
n
×
m
n×m
n×m的矩阵,现在要你从里面找出一个
k
×
k
k×k
k×k的矩阵,使得这个矩阵的最大值减去最小值最大。
n
,
m
≤
1
e
3
n,m\leq1e3
n,m≤1e3。
如果只是一个序列,维护长度为
k
k
k的区间的最大值减去最小值。直接用两个单调队列分别维护这个滑动窗口即可。那么要维护一个矩形
k
×
n
k×n
k×n的矩形的最大值和最小值,我们可以把每个
k
×
1
k×1
k×1的矩形压缩成一个点,最大值就是其中的最大值,最小值就是其中的最小值。
直接暴力求仍然是
O
(
n
m
k
)
O(nmk)
O(nmk)的,不如对每一列用单调队列预处理出这一段的最大值和最小值。这样时间复杂度就是
O
(
n
m
)
O(nm)
O(nm)的。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const ll INF=LONG_LONG_MAX;
const int N=1e3+7;
int mp[N][N];
int Ma[N][N],Mi[N][N];
int qmax[N],qmin[N];
int ma[N],mi[N];
int h1=1,t1=0;
int h2=1,t2=0;
int tot=0;
int main() {
int n,m,k;
int ans=2e9;
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=n;i++) {
for(int j=1;j<=m;j++) {
scanf("%d",&mp[i][j]);
}
}
for(int j=1;j<=m;j++) {
tot=0;
int h1=1,t1=0;
int h2=1,t2=0;
for(int i=1;i<=n;i++) {
while(t1-h1+1>0&&mp[qmax[t1]][j]<=mp[i][j]) t1--;
while(t2-h2+1>0&&mp[qmin[t2]][j]>=mp[i][j]) t2--;
qmax[++t1]=i;
qmin[++t2]=i;
while(t1-h1+1>0&&qmax[h1]<i-k+1) h1++;
while(t2-h2+1>0&&qmin[h2]<i-k+1) h2++;
if(i>=k) {
++tot;
Ma[tot][j]=mp[qmax[h1]][j];
Mi[tot][j]=mp[qmin[h2]][j];
}
}
}
for(int i=1;i<=tot;i++) {
for(int j=1;j<=m;j++) {
ma[j]=Ma[i][j];
mi[j]=Mi[i][j];
}
int h1=1,t1=0;
int h2=1,t2=0;
for(int j=1;j<=m;j++) {
while(t1-h1+1>0&&ma[qmax[t1]]<=ma[j]) t1--;
while(t2-h2+1>0&&mi[qmin[t2]]>=mi[j]) t2--;
qmax[++t1]=j;
qmin[++t2]=j;
while(qmax[h1]<j-k+1) h1++;
while(qmin[h2]<j-k+1) h2++;
if(j>=k) {
ans=min(ans,ma[qmax[h1]]-mi[qmin[h2]]);
}
}
}
printf("%d\n",ans);
return 0;
}