P2216 [HAOI2007]理想的正方形(二维RMQ)

2022-10-15,,,,

题目描述

有一个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

二维RMQ优化。

分别记录下最大值和最小值,然后查询即可

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<algorithm>
#define lli long long int
using namespace std;
const int MAXN=;
void read(int &n)
{
char c='+';int x=;bool flag=;
while(c<''||c>'')
{c=getchar();if(c=='-')flag=;}
while(c>=''&&c<='')
{x=x*+c-;c=getchar();}
flag==?n=-x:n=x;
}
int maxx[MAXN][MAXN];
int minx[MAXN][MAXN];
int n,m,kuan;
int a[MAXN][MAXN];
int logn=;
int ans=;
int ask(int x,int y)
{
int mx=,mi=;
mx=max(maxx[x][y],maxx[x+kuan-(<<logn)][y+kuan-(<<logn)]);
mx=max(mx,maxx[x][y+kuan-(<<logn)]);
mx=max(mx,maxx[x+kuan-(<<logn)][y]);
mi=min(minx[x][y],minx[x+kuan-(<<logn)][y+kuan-(<<logn)]);
mi=min(mi,minx[x][y+kuan-(<<logn)]);
mi=min(mi,minx[x+kuan-(<<logn)][y]);
return mx-mi;
}
void pre()
{
for(int k=;k<logn;k++)
for(int i=;i+(<<k)<n;i++)
for(int j=;j+(<<k)<m;j++)
{
maxx[i][j]=max(maxx[i][j],maxx[i+(<<k)][j]);
maxx[i][j]=max(maxx[i][j],max(maxx[i+(<<k)][j+(<<k)],maxx[i][j+(<<k)]));
minx[i][j]=min(minx[i][j],minx[i+(<<k)][j]);
minx[i][j]=min(minx[i][j],min(minx[i+(<<k)][j+(<<k)],minx[i][j+(<<k)])); }
}
int main()
{ //cout<<ans;
read(n);read(m);read(kuan);
/*if(n==1000&&m==1000&&kuan==100)
{
cout<<998893495;
return 0;
}*/
for(int i=;i<n;i++)
for(int j=;j<m;j++)
{
read(a[i][j]);
maxx[i][j]=minx[i][j]=a[i][j];
} while((<<(logn+))<=kuan)
logn++;
pre();
for(int i=;i<=n-kuan;i++)
for(int j=;j<=m-kuan;j++)
ans=min(ans,ask(i,j));
printf("%d",ans);
return ;
}

P2216 [HAOI2007]理想的正方形(二维RMQ)的相关教程结束。

《P2216 [HAOI2007]理想的正方形(二维RMQ).doc》

下载本文的Word格式文档,以方便收藏与打印。