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;
}

posted on 2022-08-11 18:29  gryzy  阅读(160)  评论(0编辑  收藏  举报

导航