P2216 [HAOI2007] 理想的正方形(单调队列)
Posted li_wen_zhuo
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P2216 [HAOI2007] 理想的正方形(单调队列)相关的知识,希望对你有一定的参考价值。
题目描述
有一个a * b的整数组成的矩阵,现请你从中找出一个n * n的正方形区域,使得该区域所有数中的最大值和最小值的差最小。
输入格式
第一行为3个整数,分别表示a,b,n的值
第二行至第a+1行每行为b个非负整数,表示矩阵中相应位置上的数。每行相邻两数之间用一空格分隔。
输出格式
仅一个整数,为ab矩阵中所有“nn正方形区域中的最大整数和最小整数的差值”的最小值。
样例
输入 #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
题目分析
这道题看似比较复杂,要求出每个n * n的二维区间的最大值和最小值。我们可以通过求两次单调队列的方法获得答案:
设x[i][j] //表示第i行中j到j+n-1区间中的最小值,X[i][j] //表示第i行中j到j+n-1区间中的最大值
。这样我们可以用单调队列在O(a * b)的复杂度内求出这两个数组。
然后在x[][]和X[][]上求出y[i][j] //表示第j列中i到i+n-1区间中的最小值,Y[i][j] //表示第j列中i到i+n-1区间中的最大值
。这样求出的y[i][j],就表示矩阵[i,i+n-1][j,j+n-1]中的最小值了(Y[][]同理)。
代码如下
#include <iostream>
#include <cmath>
#include <cstdio>
#include <set>
#include <string>
#include <cstring>
#include <map>
#include <algorithm>
#include <stack>
#include <queue>
#include <bitset>
#define LL long long
#define ULL unsigned long long
#define PII pair<int,int>
#define PLL pair<LL,LL>
#define PDD pair<double,double>
#define x first
#define y second
using namespace std;
const int N=1e3+5,INF=1e9;
int m[N][N],q[N],Q[N];
int x[N][N],X[N][N];
int y[N][N],Y[N][N];
int main()
{
cin.tie(0);
ios::sync_with_stdio(false);
int n,a,b;
cin>>a>>b>>n;
for(int i=1;i<=a;i++)
for(int j=1;j<=b;j++)
cin>>m[i][j];
for(int i=1;i<=a;i++)
{
int h,t,H,T;
h=t=H=T=q[1]=Q[1]=1; //初始化
for(int j=2;j<=b;j++) //单调队列求出最大值和最小值
{
while(h<=t&&m[i][q[t]]>=m[i][j]) t--;
while(H<=T&&m[i][Q[T]]<=m[i][j]) T--;
q[++t]=j,Q[++T]=j;
if(j-q[h]>=n) h++;
if(j-Q[H]>=n) H++;
if(j>=n) x[i][j-n+1]=m[i][q[h]],X[i][j-n+1]=m[i][Q[H]]; //将答案记录到x[][]和X[][]中
}
}
for(int j=1;j<=b-n+1;j++)
{
int h,t,H,T;
h=t=H=T=q[1]=Q[1]=1; //初始化
for(int i=2;i<=a;i++) //在x[][]的基础上,用单调队列按列求出最小值数组y[][](Y同理)
{
while(h<=t&&x[q[t]][j]>=x[i][j]) t--;
while(H<=T&&X[Q[T]][j]<=X[i][j]) T--;
q[++t]=i,Q[++T]=i;
if(i-q[h]>=n) h++;
if(i-Q[H]>=n) H++;
if(i>=n) y[i-n+1][j]=x[q[h]][j],Y[i-n+1][j]=X[Q[H]][j];
}
}
int ans=INF;
for(int i=1;i<=a-n+1;i++) //枚举每一个矩阵最值,求出差值的最小值
for(int j=1;j<=b-n+1;j++)
ans=min(ans,Y[i][j]-y[i][j]);
cout<<ans<<endl;
return 0;
}
以上是关于P2216 [HAOI2007] 理想的正方形(单调队列)的主要内容,如果未能解决你的问题,请参考以下文章