理想的正方形 HAOI2007(二维RMQ)
理想的正方形
省队选拔赛河南
时间限制: 1 s
空间限制: 256000 KB
题目等级 : 大师 Master
题目描述 Description
有一个a*b的整数组成的矩阵,现请你从中找出一个n*n的正方形区域,使得该区域所有数中的最大值和最小值的差最小。
输入描述 Input Description
第一行为3个整数,分别表示a,b,n的值
第二行至第a+1行每行为b个非负整数,表示矩阵中相应位置上的数。每行相邻两数之间用一空格分隔。
输出描述 Output Description
仅一个整数,为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
数据范围及提示 Data Size & Hint
(1)矩阵中的所有数都不超过1,000,000,000
(2)20%的数据2<=a,b<=100,n<=a,n<=b,n<=10
(3)100%的数据2<=a,b<=1500,n<=a,n<=b,n<=100
/* 嗯,脑补二维RMQ fail,挂成暴力分。 一维是维护一个区间,二维是维护一个矩阵。 由于这个题是小正方形,三维数组即可。二维RMQ略麻烦... */ #include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<cstdlib> #define x2 x1+n-1-(1<<m)+1 #define y2 y1+n-1-(1<<m)+1 using namespace std; void read(int &x) { int f=1;x=0;char c=getchar(); while(!isdigit(c)){if(c=='-')f=-1;c=getchar();} while(isdigit(c)){x=(x<<3)+(x<<1)+c-'0';c=getchar();} x*=f; } void out(int x) { if(!x){putchar('0');return;} if(x<0){x=~x+1;putchar('-');} char c[30]= {0}; while(x)c[++c[0]]=x%10+48,x/=10; while(c[0])putchar(c[c[0]--]); } const int inf=1e3+29; int i,j,k,m; int g[inf][inf][12]; int f[inf][inf][12]; int x,y,n; int ans=0x7fffffff; int query(int x1,int y1) { int maxn=0,minn=0x7fffffff; maxn=max(f[x1][y1][m],f[x2][y2][m]); maxn=max(maxn,f[x1][y2][m]); maxn=max(maxn,f[x2][y1][m]); minn=min(g[x1][y1][m],g[x2][y2][m]); minn=min(minn,g[x1][y2][m]); minn=min(minn,g[x2][y1][m]); return maxn-minn; } int main() { read(y);read(x); read(n);m=log(n)/log(2); for(i=1; i<=y; i++) for(j=1; j<=x; j++) { read(f[j][i][0]); g[j][i][0]=f[j][i][0]; } for(k=1; k<=12; k++) for(i=1; i+(1<<k)-1<=x; i++) for(j=1; j+(1<<k)-1<=y; j++) { f[i][j][k]=max(f[i][j][k-1],f[i+(1<<(k-1))][j+(1<<(k-1))][k-1]); f[i][j][k]=max(f[i][j][k],f[i+(1<<(k-1))][j][k-1]); f[i][j][k]=max(f[i][j][k],f[i][j+(1<<(k-1))][k-1]); g[i][j][k]=min(g[i][j][k-1],g[i+(1<<(k-1))][j+(1<<(k-1))][k-1]); g[i][j][k]=min(g[i][j][k],g[i+(1<<(k-1))][j][k-1]); g[i][j][k]=min(g[i][j][k],g[i][j+(1<<(k-1))][k-1]); } for(i=1; i+n-1<=x; i++) for(j=1; j+n-1<=y; j++) ans=min(ans,query(i,j)); out(ans); return 0; }
折花枝,恨花枝,准拟花开人共卮,开时人去时。
怕相思,已相思,轮到相思没处辞,眉间露一丝。