1047: [HAOI2007]理想的正方形
Time Limit: 10 Sec Memory Limit: 162 MB
Submit: 3563 Solved: 1967
[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
题解
先用单调队列求出点(i,j)向下n个数中的最大值和最小值,再用单调队列维护一个n*n矩阵中的最大值和最小值,求出n*n的矩阵最大值减最小值的最小值。
代码
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<iostream> using namespace std; const int N=1005,inf=0x3f3f3f3f; int a,b,n,m,ans=inf; int map[N][N],mx[N][N],mn[N][N],qx[N],qn[N]; int main(){ scanf("%d%d%d",&a,&b,&n); for(int i=1;i<=a;i++){ for(int j=1;j<=b;j++){ scanf("%d",&map[i][j]); } } int lx,rx,ln,rn; for(int i=1;i<=b;i++){ lx=ln=1,rx=rn=0; qx[lx]=qx[rx]=qx[ln]=qn[rn]=0; for(int j=1;j<=n;j++){ while(lx<=rx&&map[j][i]>map[qx[rx]][i])rx--; qx[++rx]=j; while(ln<=rn&&map[j][i]<map[qn[rn]][i])rn--; qn[++rn]=j; } for(int j=n;j<=a;j++){ while(lx<=rx&&qx[lx]<j-n+1)lx++; while(lx<=rx&&map[j][i]>map[qx[rx]][i])rx--; qx[++rx]=j; mx[j-n+1][i]=map[qx[lx]][i]; while(ln<=rn&&qn[ln]<j-n+1)ln++; while(ln<=rn&&map[j][i]<map[qn[rn]][i])rn--; qn[++rn]=j; mn[j-n+1][i]=map[qn[ln]][i]; } } for(int i=1;i<=a-n+1;i++){ lx=ln=1,rx=rn=0; qx[lx]=qx[rx]=qn[ln]=qn[rn]=0; for(int j=1;j<=n;j++){ while(lx<=rx&&mx[i][j]>mx[i][qx[rx]])rx--; qx[++rx]=j; while(ln<=rn&&mn[i][j]<mn[i][qn[rn]])rn--; qn[++rn]=j; } for(int j=n;j<=b;j++){ while(lx<=rx&&qx[lx]<j-n+1)lx++; while(lx<=rx&&mx[i][j]>mx[i][qx[rx]])rx--; qx[++rx]=j; while(ln<=rn&&qn[ln]<j-n+1)ln++; while(ln<=rn&&mn[i][j]<mn[i][qn[rn]])rn--; qn[++rn]=j; ans=min(ans,mx[i][qx[lx]]-mn[i][qn[ln]]); } } printf("%d ",ans); return 0; }