题目描述
有一个a*b的整数组成的矩阵,现请你从中找出一个n*n的正方形区域,使得该区域所有数中的最大值和最小值的差最小。
输入输出格式
输入格式:
第一行为3个整数,分别表示a,b,n的值
第二行至第a+1行每行为b个非负整数,表示矩阵中相应位置上的数。每行相邻两数之间用一空格分隔。
输出格式:
仅一个整数,为a*b矩阵中所有“n*n正方形区域中的最大整数和最小整数的差值”的最小值。
输入输出样例
输入样例#1:
5 4 2 1 2 5 6 0 17 16 0 16 17 2 1 2 10 2 1 1 2 2 2
输出样例#1:
1
说明
问题规模
(1)矩阵中的所有数都不超过1,000,000,000
(2)20%的数据2<=a,b<=100,n<=a,n<=b,n<=10
(3)100%的数据2<=a,b<=1000,n<=a,n<=b,n<=100
/* 就是为了这个题目学的st表 st表能够维护数列的某个地方往后2的整数次方的极值 这个题目用st表来维护矩阵中某个元素往右下方二次方整数边长的矩阵元素的极值 然后四块合并 O1 查询四块原理就和ST表一样了 */ #include<cstdio> #include<algorithm> #include<iostream> #include<cmath> using namespace std; int maxx[1001][1001][13]; int minn[1001][1001][13]; int read() { int num = 0; char c = getchar(); while(c > '9' || c < '0')c = getchar(); while(c <= '9' && c >= '0') { num *= 10; num += c - '0'; c = getchar(); } return num; } int n,m,k,p; int ans = 0x7fffffff; int main() { n = read();m = read();k = read(); for(int i = 1;i <= n;i++) for(int j = 1;j <= m;j++) maxx[i][j][0] = minn[i][j][0] = read(); p = log(k) / log(2); for(int i = 1;i <= 11;i++) { for(int j = 1;j + (1 << i) - 1 <= n;j++) for(int z = 1;z + (1 << i) - 1<= m;z++) { maxx[j][z][i] = max(maxx[j][z][i - 1], max(maxx[j][z + (1 << (i - 1))][i - 1], max(maxx[j + (1 << (i - 1))][z + (1 << (i - 1))][i - 1], maxx[j + (1 << (i - 1))][z][i - 1]))); minn[j][z][i] = min(minn[j][z][i - 1], min(minn[j][z + (1 << (i - 1))][i - 1], min(minn[j + (1 << (i - 1))][z + (1 << (i - 1))][i - 1], minn[j + (1 << (i - 1))][z][i - 1]))); } } for(int x = 1;x + k - 1 <= n;x++) for(int y = 1;y + k - 1 <= m;y++) { ans = min(ans, max(maxx[x][y][p], max(maxx[x][y + k - (1 << p)][p], max(maxx[x + k - (1 << p)][y][p], maxx[x + k - (1 << p)][y + k - (1 << p)][p]))) - min(minn[x][y][p], min(minn[x][y + k - (1 << p)][p], min(minn[x + k - (1 << p)][y][p], minn[x + k - (1 << p)][y + k - (1 << p)][p])))); } printf("%d",ans); return 0; }