- 题意:有一个a*b的整数组成的矩阵,现请你从中找出一个n*n的正方形区域。
- 使得该区域所有数中的最大值和最小值的差最小。
- 思路:先用单调队列维护行,得到两个新的矩阵,每个点的含义是从此处往后k个的最大值(或最小值)。
- 在对这两个新的矩阵进行列单调队列维护最值得到两个新的矩阵此时每个点的含义就是从此处开始的大小n*n的区域内的
- 最大值(最小值)。最后暴力枚举一下求一个最值差最小即可。
-
#include<bits/stdc++.h> using namespace std; #define inf 0x3f3f3f3f #define maxn 1234 int a[maxn][maxn],n,m; int miii[maxn][maxn],k; int ans1[maxn][maxn]; int qmin[maxn],l,r; int qmax[maxn],s,t,ans; int maaa[maxn][maxn]; int ans2[maxn][maxn]; void cal() { for(int i=1; i<=n; i++) { t=r=-1; s=l=0; for(int j=m; j>0; j--) { while(l<=r&&a[i][j]<a[i][qmin[r]])r--; qmin[++r]=j; while(qmin[l]-qmin[r]+1>k)l++; while(s<=t&&a[i][j]>a[i][qmax[t]])t--; qmax[++t]=j; while(qmax[s]-qmax[t]+1>k)s++; if(m-j+1>=k) { miii[i][j]=a[i][qmin[l]]; maaa[i][j]=a[i][qmax[s]]; } } } } void ok() { for(int j=1; j<=m-k+1; j++) { t=r=-1; s=l=0; for(int i=n; i>0; i--) { while(l<=r&&miii[i][j]<miii[qmin[r]][j])r--; qmin[++r]=i; while(qmin[l]-qmin[r]+1>k)l++; while(s<=t&&maaa[i][j]>maaa[qmax[t]][j])t--; qmax[++t]=i; while(qmax[s]-qmax[t]+1>k)s++; if(n-i+1>=k) { ans1[i][j]=miii[qmin[l]][j]; ans2[i][j]=maaa[qmax[s]][j]; } } } } 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]); cal(); ok(); ans=inf; for(int i=1; i<=n-k+1; i++) for(int j=1; j<=m-k+1; j++) ans=min(ans,ans2[i][j]-ans1[i][j]); printf("%d\n",ans); return 0; }