Time Limit: 10 Sec Memory Limit: 162 MB
Submit: 4075 Solved: 2277
[Submit][Status][Discuss]
Description
有一个a*b的整数组成的矩阵,现请你从中找出一个n*n的正方形区域,使得该区域所有数中的最大值和最小值
的差最小。
Input
第一行为3个整数,分别表示a,b,n的值第二行至第a+1行每行为b个非负整数,表示矩阵中相应位置上的数。每
行相邻两数之间用一空格分隔。
100%的数据2<=a,b<=1000,n<=a,n<=b,n<=1000
Output
仅一个整数,为a*b矩阵中所有“n*n正方形区域中的最大整数和最小整数的差值”的最小值。
Sample Input
5 4 2
1 2 5 6
0 17 16 0
16 17 2 1
2 10 2 1
1 2 2 2
Sample Output
1
二维单调队列
先计算每行前n个点的最大值和最小值,用单调队列维护。
然后按列的顺序计算每个点作为右下角时,矩阵的最大值和最小值。
简单来说,就是多次运用单调队列,将二维矩阵压缩为一维矩阵求解
1 #include<iostream> 2 #include<cstdio> 3 using namespace std; 4 5 const int MAXN=1000+5; 6 const int INF=0x7fffffff; 7 8 int a,b,n,ans=INF; 9 int s[MAXN][MAXN],mx[MAXN][MAXN],mn[MAXN][MAXN]; 10 int val[MAXN],pos[MAXN],x[MAXN],y[MAXN]; 11 12 int main() 13 { 14 scanf("%d %d %d",&a,&b,&n); 15 for(int i=1;i<=a;i++) 16 for(int j=1;j<=b;j++) 17 scanf("%d",&s[i][j]); 18 int l,r; 19 for(int i=1;i<=a;i++) 20 { 21 l=1,r=1; 22 for(int j=1;j<=b;j++) 23 { 24 while(l<r&&val[r-1]<=s[i][j]) r--; 25 val[r]=s[i][j];pos[r]=j;r++; 26 if(pos[l]==j-n) l++; 27 if(j>=n) mx[i][j]=val[l]; 28 } 29 l=1,r=1; 30 for(int j=1;j<=b;j++) 31 { 32 while(l<r&&val[r-1]>=s[i][j]) r--; 33 val[r]=s[i][j];pos[r]=j;r++; 34 if(pos[l]==j-n) l++; 35 if(j>=n) mn[i][j]=val[l]; 36 } 37 } 38 for(int i=n;i<=b;i++) 39 { 40 l=1,r=1; 41 for(int j=1;j<=a;j++) 42 { 43 while(l<r&&val[r-1]<=mx[j][i]) r--; 44 val[r]=mx[j][i];pos[r]=j;r++; 45 if(pos[l]==j-n) l++; 46 if(j>=n) x[j]=val[l]; 47 } 48 l=1,r=1; 49 for(int j=1;j<=a;j++) 50 { 51 while(l<r&&val[r-1]>=mn[j][i]) r--; 52 val[r]=mn[j][i];pos[r]=j;r++; 53 if(pos[l]==j-n) l++; 54 if(j>=n) y[j]=val[l]; 55 } 56 for(int i=n;i<=a;i++) ans=min(ans,x[i]-y[i]); 57 } 58 printf("%d\n",ans); 59 return 0; 60 }
原文地址:https://www.cnblogs.com/InWILL/p/9337841.html
时间: 2024-10-07 12:08:29