传送门biu~
对于每一行,用两个单调队列求出以每个点为结尾的长度为n的区间的最大、最小值。
再对于每一列刚才求出的值,用两个单调队列求长度为n的区间最大、最小值。
此时便求出了以每个点为右下角的n*n矩形的最大最小值。
时间复杂度O(n)。
#include<bits/stdc++.h>
#define N 1005
#define pa pair<int,int>
using namespace std;
int n,m,k,ans=2e9,a[N][N],Min[N][N],Max[N][N],Min2[N][N],Max2[N][N];
deque<pa>qMin,qMax;
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){
qMin.clear(); qMax.clear();
for(int j=1;j<=m;++j){
while(!qMin.empty() && qMin.front().second<=j-k) qMin.pop_front();
while(!qMin.empty() && qMin.back().first>=a[i][j]) qMin.pop_back();
qMin.push_back(pa(a[i][j],j));
Min[i][j]=qMin.front().first;
while(!qMax.empty() && qMax.front().second<=j-k) qMax.pop_front();
while(!qMax.empty() && qMax.back().first<=a[i][j]) qMax.pop_back();
qMax.push_back(pa(a[i][j],j));
Max[i][j]=qMax.front().first;
}
}
for(int j=1;j<=m;++j){
qMin.clear(); qMax.clear();
for(int i=1;i<=n;++i){
while(!qMin.empty() && qMin.front().second<=i-k) qMin.pop_front();
while(!qMin.empty() && qMin.back().first>=Min[i][j]) qMin.pop_back();
qMin.push_back(pa(Min[i][j],i));
Min2[i][j]=qMin.front().first;
while(!qMax.empty() && qMax.front().second<=i-k) qMax.pop_front();
while(!qMax.empty() && qMax.back().first<=Max[i][j]) qMax.pop_back();
qMax.push_back(pa(Max[i][j],i));
Max2[i][j]=qMax.front().first;
}
}
for(int i=k;i<=n;++i)
for(int j=k;j<=m;++j)
ans=min(ans,Max2[i][j]-Min2[i][j]);
printf("%d\n",ans);
return 0;
}