luogu2216 二维ST表
[HAOI2007]理想的正方形
题目描述
有一个 \(a \times b\) 的整数组成的矩阵,现请你从中找出一个 \(n \times n\) 的正方形区域,使得该区域所有数中的最大值和最小值的差最小。
输入格式
第一行为 \(3\) 个整数,分别表示 \(a,b,n\) 的值。
第二行至第 \(a+1\) 行每行为 \(b\) 个非负整数,表示矩阵中相应位置上的数。每行相邻两数之间用一空格分隔。
输出格式
仅一个整数,为 \(a \times b\) 矩阵中所有“ \(n \times n\) 正方形区域中的最大整数和最小整数的差值”的最小值。
样例 #1
样例输入 #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,000,000,000\)。
\(20\%\) 的数据 \(2 \le a,b \le 100,n \le a,n \le b,n \le 10\)。
\(100\%\) 的数据 \(2 \le a,b \le 1000,n \le a,n \le b,n \le 100\)。
二维ST表,就是用来在二维表格中查找最大最小值。和ST表一样,都是倍增。
初始化\(O(n^2\log n)\),每次查询\(O(1)\)
初始化:
f[i][j][k]表示(i,j)点左上角的边长为\(2^k\)的正方形区域内的最大值。
f[i][j][k]=max(f[i][j][k-1],f[i-(1<<(k-1))][j][k-1],f[i][j-(1<<(k-1))][k-1],f[i-(1<<(k-1))][j-(1<<(k-1))][k-1])
查询:
fx[i][j][k]表示(i,j)点左上角的边长为k的正方形区域内的最大值。
fx[i][j][k]=max(fx[i][j][lgk],fx[i-k+(1<<lgk)][j][lgk],fx[i][j-k+(1<<lgk)][lgk],fx[i-k+(1<<lgk)][j-k+(1<<lgk)][lgk])
#include<bits/stdc++.h>
using namespace std;
const int maxn=1010;
int sz[maxn][maxn],fx[maxn][maxn][12],fn[maxn][maxn][12];
int a,b,n;
int lg[maxn];
int maxf(int a,int b,int c,int d)
{
return max(max(a,b),max(c,d));
}
int minf(int a,int b,int c,int d)
{
return min(min(a,b),min(c,d));
}
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",&sz[i][j]);
fx[i][j][0]=fn[i][j][0]=sz[i][j];
}
int tpn=min(a,b),tpx=max(a,b);
for(int i=2;i<=tpx;++i)lg[i]=lg[i/2]+1;
for(int l=1;l<=lg[tpx];++l)
for(int i=(1<<l);i<=a;++i)
for(int j=(1<<l);j<=b;++j)
{
fn[i][j][l]=minf(fn[i][j][l-1],fn[i-(1<<(l-1))][j][l-1],fn[i][j-(1<<(l-1))][l-1],fn[i-(1<<(l-1))][j-(1<<(l-1))][l-1]);
fx[i][j][l]=maxf(fx[i][j][l-1],fx[i-(1<<(l-1))][j][l-1],fx[i][j-(1<<(l-1))][l-1],fx[i-(1<<(l-1))][j-(1<<(l-1))][l-1]);
}
int ans=0x7fffffff,lgn=lg[n];
for(int x,y,i=n;i<=a;++i)
for(int j=n;j<=b;++j)
{
x=minf(fn[i][j][lgn],fn[i-n+(1<<lgn)][j][lgn],fn[i][j-n+(1<<lgn)][lgn],fn[i-n+(1<<lgn)][j-n+(1<<lgn)][lgn]);
y=maxf(fx[i][j][lgn],fx[i-n+(1<<lgn)][j][lgn],fx[i][j-n+(1<<lgn)][lgn],fx[i-n+(1<<lgn)][j-n+(1<<lgn)][lgn]);
ans=min(ans,y-x);
}
cout<<ans<<endl;
return 0;
}