如果是一维的,我们可以用单调队列O(n)解决这个问题,扫一遍求出最小值和最大值,再扫一遍更新答案。二维的同理,我们可以做到O(n2) 先维护出各行的最小值,再维护此时各列(也即此时的矩形区域)的最小值。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
#define N 2010
#define pa pair<int,int>
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return x*f;
}
int n,m,k,mn[N][N],mx[N][N];
pa q1[N],q2[N];
int main(){
// freopen("a.in","r",stdin);
n=read();m=read();k=read();
for(int j=1;j<=n;++j){
int h1=1,t1=0,h2=1,t2=0;
for(int i=1;i<=m;++i){
int x=read();
while(h1<=t1&&q1[h1].second<i-k+1) ++h1;
while(h1<=t1&&q1[t1].first>=x) --t1;
q1[++t1]=make_pair(x,i);if(i>=k)mn[j][i-k+1]=q1[h1].first;
while(h2<=t2&&q2[h2].second<i-k+1) ++h2;
while(h2<=t2&&q2[t2].first<=x) --t2;
q2[++t2]=make_pair(x,i);if(i>=k)mx[j][i-k+1]=q2[h2].first;
}
}m=m-k+1;
for(int j=1;j<=m;++j){
int h1=1,t1=0,h2=1,t2=0;
for(int i=1;i<=n;++i){
int x=mn[i][j];
while(h1<=t1&&q1[h1].second<i-k+1) ++h1;
while(h1<=t1&&q1[t1].first>=x) --t1;
q1[++t1]=make_pair(x,i);if(i>=k)mn[i-k+1][j]=q1[h1].first;
x=mx[i][j];
while(h2<=t2&&q2[h2].second<i-k+1) ++h2;
while(h2<=t2&&q2[t2].first<=x) --t2;
q2[++t2]=make_pair(x,i);if(i>=k)mx[i-k+1][j]=q2[h2].first;
}
}n=n-k+1;int ans=inf;
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j) ans=min(ans,mx[i][j]-mn[i][j]);
printf("%d\n",ans);
return 0;
}