bzoj:1047: [HAOI2007]理想的正方形
Description
有一个a*b的整数组成的矩阵,现请你从中找出一个n*n的正方形区域,使得该区域所有数中的最大值和最小值的差最小。
Input
第一行为3个整数,分别表示a,b,n的值第二行至第a+1行每行为b个非负整数,表示矩阵中相应位置上的数。每行相邻两数之间用一空格分隔。
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
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个位置的最大值和最小值,最后再单调队列统计一下就好啦
#include<cstdio> #include<algorithm> using namespace std; int a,b,n,map[1001][1001],la[1001][1001],li[1001][1001],q[1001],num[1001],w[1001],nm[1001],fi,len,fw,lw,ans=1000000001,o,p; inline int read(){ p=0;o=getchar(); while(o<'0'||o>'9') o=getchar(); while(o>='0'&&o<='9') p=p*10+o-48,o=getchar(); return p; } inline int max(int x,int y){return x>y?x:y;} int main(){ register int i,j; a=read();b=read();n=read(); for (i=1;i<=a;i++) for (j=1;j<=b;j++) map[i][j]=read(); for (i=1;i<=a;i++){ fi=1;len=0; for (j=1;j<=b;j++){ while ((len>=fi)&&(q[len]<=map[i][j])) len--; q[++len]=map[i][j]; num[len]=j; while(num[fi]<=j-n) fi++; la[i][j]=q[fi]; } } for (i=1;i<=a;i++){ fi=1;len=0; for (j=1;j<=b;j++){ while ((len>=fi)&&(q[len]>=map[i][j])) len--; q[++len]=map[i][j]; num[len]=j; while(num[fi]<=j-n) fi++; li[i][j]=q[fi]; } } for (j=n;j<=b;j++){ fi=fw=1;len=lw=0; for (i=1;i<=a;i++){ while((len>=fi)&&(q[len]<=la[i][j])) len--; q[++len]=la[i][j]; num[len]=i; while(num[fi]<=i-n) fi++; while((lw>=fw)&&(w[lw]>=li[i][j])) lw--; w[++lw]=li[i][j]; nm[lw]=i; while(nm[fw]<=i-n) fw++; if (i>=n) ans=min(q[fi]-w[fw],ans); } } printf("%d\n",ans); }