题意: 给一个矩阵,给出行列和每个数,再给出一个N,求出所有N*N的子矩阵中最大值最小值之差的最小值
解析: 暴力枚举肯定不行,这题可以用二维单调队列做,把同一行的连续N个点缩成一个点保存最大最小值预处理
,用单调队列即可实现,再对整个矩阵进行枚举,再用一次单调队列。
代码
#include<cstdio> #include<cstring> #include<algorithm> #include<vector> #include<cmath> using namespace std; const int INF=1e9+7; const int maxn=1002; int row,col,N; int A[maxn][maxn]; int Min[maxn][maxn],Max[maxn][maxn]; int q1[maxn],q2[maxn]; int f1,f2,r1,r2; void init() //预处理 { for(int i=1;i<=row;i++) { f1=1,r1=0; f2=1,r2=0; for(int j=1;j<N;j++) { while(r1>=f1&&A[i][q1[r1]]>=A[i][j]) r1--; q1[++r1]=j; while(r2>=f2&&A[i][q2[r2]]<=A[i][j]) r2--; q2[++r2]=j; } for(int j=N;j<=col;j++) { while(r1>=f1&&A[i][q1[r1]]>=A[i][j]) r1--; q1[++r1]=j; while(q1[f1]+N<=j) f1++; Min[i][j-N+1]=A[i][q1[f1]]; //缩点后的最小值 while(r2>=f2&&A[i][q2[r2]]<=A[i][j]) r2--; q2[++r2]=j; while(q2[f2]+N<=j) f2++; Max[i][j-N+1]=A[i][q2[f2]]; //缩点后的最大值 } } } int solve() { int ret=INF; for(int j=1;j+N-1<=col;j++) //对同一列进行枚举 { f1=1,r1=0; f2=1,r2=0; int minv=INF,maxv=-INF; for(int i=1;i<N;i++) { while(r1>=f1&&Min[q1[r1]][j]>=Min[i][j]) r1--; q1[++r1]=i; while(r2>=f2&&Max[q2[r2]][j]<=Max[i][j]) r2--; q2[++r2]=i; } for(int i=N;i<=row;i++) { while(r1>=f1&&Min[q1[r1]][j]>=Min[i][j]) r1--; q1[++r1]=i; while(q1[f1]+N<=i) f1++; minv=Min[q1[f1]][j]; while(r2>=f2&&Max[q2[r2]][j]<=Max[i][j]) r2--; q2[++r2]=i; while(q2[f2]+N<=i) f2++; maxv=Max[q2[f2]][j]; ret=min(ret,maxv-minv); } } return ret; } int main() { scanf("%d%d%d",&row,&col,&N); for(int i=1;i<=row;i++) for(int j=1;j<=col;j++) scanf("%d",&A[i][j]); init(); printf("%d ",solve()); return 0; }