Description
有一个a*b的整数组成的矩阵,现请你从中找出一个n*n的正方形区域,使得该区域所有数中的最大值和最小值
的差最小。
第一行为3个整数,分别表示a,b,n的值第二行至第a+1行每行为b个非负整数,表示矩阵中相应位置上的数。每
行相邻两数之间用一空格分隔。
100%的数据2<=a,b<=1000,n<=a,n<=b,n<=1000
解:
两次单调队列
1、第一次单调队列对每一列滑动窗口求最值
2、第二次用第一步得到的矩阵再次对每一行做滑动窗口我们就得到了原始矩阵的最值了
#include<stdio.h>
#include<iostream>
#include<string.h>
using namespace std;
#define ll long long
#define en '\n'
const int maxn =1e3+10;
const int inf=0x3f3f3f3f;
int a[maxn][maxn],q[maxn],A[maxn][maxn],B[maxn][maxn],AA[maxn][maxn],BB[maxn][maxn];
inline int read(){
int x=0,f=1; char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-1; ch=getchar();}
while(isdigit(ch)) {x=x*10+ch-'0'; ch=getchar();}
return x*f;
}
int R,C,k;
signed main()
{
#ifdef local
freopen("input2.txt","r",stdin);
#endif
#define int register int
cin>>R>>C>>k;
for(int i=1;i<=R;i++){
for(int j=1;j<=C;j++){
a[i][j]=read();
}//cout<<en;
}
int ind,indd,l,r;
for(int j=1;j<=C;j++){
l=1,r=0,ind=0;
for(int i=1;i<=R;i++){
while(l<=r and i-q[l]>=k)l+=1;
while(l<=r and a[q[r]][j]>=a[i][j])r-=1;
q[++r]=i;
if(i>=k){
A[++ind][j]=a[q[l]][j];
}
}
}
for(int j=1;j<=C;j++){
l=1,r=0,ind=0;
for(int i=1;i<=R;i++){
while(l<=r and i-q[l]>=k)l+=1;
while(l<=r and a[q[r]][j]<=a[i][j])r-=1;
q[++r]=i;
if(i>=k){
B[++ind][j]=a[q[l]][j];
}
}
}
for(int i=1;i<=ind;i++){
l=1,r=0,indd=0;
for(int j=1;j<=C;j++){
while(l<=r and j-q[l]>=k)l+=1;
while(l<=r and A[i][q[r]]>=A[i][j])r-=1;
q[++r]=j;
if(j>=k){
AA[i][++indd]=A[i][q[l]];
}
}
}
int ans=inf;
for(int i=1;i<=ind;i++){
l=1,r=0,indd=0;
for(int j=1;j<=C;j++){
while(l<=r and j-q[l]>=k)l+=1;
while(l<=r and B[i][q[r]]<=B[i][j])r-=1;
q[++r]=j;
if(j>=k){
BB[i][++indd]=B[i][q[l]];
ans=min(ans,BB[i][indd]-AA[i][indd]);
}
}
}
cout<<ans<<en;
return 0;
}