题解:思路,二维转一维;
先求每一行相邻k个的最值
然后相邻k个看成整体竖着再求一遍
用单调队列实现
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int maxn=1009; int n,m,k; int ans=1000000000; int a[maxn][maxn]; int mn[maxn][maxn]; int mx[maxn][maxn]; int tmp1[maxn][maxn]; int q[maxn],head,tail; 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){ head=1;tail=0; for(int j=1;j<=m;++j){ while((head<=tail)&&(j-q[head]+1>k))++head; while((head<=tail)&&(a[i][q[tail]]>=a[i][j]))--tail; q[++tail]=j; if(j>=k)tmp1[i][j-k+1]=a[i][q[head]]; } } for(int j=1;j<=m;++j){ head=1;tail=0; for(int i=1;i<=n;++i){ while((head<=tail)&&(i-q[head]+1>k))++head; while((head<=tail)&&(tmp1[q[tail]][j]>=tmp1[i][j]))--tail; q[++tail]=i; if(i>=k)mn[i-k+1][j]=tmp1[q[head]][j]; } } for(int i=1;i<=n;++i){ head=1;tail=0; for(int j=1;j<=m;++j){ while((head<=tail)&&(j-q[head]+1>k))++head; while((head<=tail)&&(a[i][q[tail]]<=a[i][j]))--tail; q[++tail]=j; if(j>=k)tmp1[i][j-k+1]=a[i][q[head]]; } } for(int j=1;j<=m;++j){ head=1;tail=0; for(int i=1;i<=n;++i){ while((head<=tail)&&(i-q[head]+1>k))++head; while((head<=tail)&&(tmp1[q[tail]][j]<=tmp1[i][j]))--tail; q[++tail]=i; if(i>=k)mx[i-k+1][j]=tmp1[q[head]][j]; } } for(int i=1;i<=n-k+1;++i){ for(int j=1;j<=m-k+1;++j){ ans=min(ans,mx[i][j]-mn[i][j]); } } cout<<ans<<endl; return 0; }