【HAOI2007】 理想的正方形 【二维 单调队列】

#1108 理想的正方形

描述
有一个ab的整数组成的矩阵,现请你从中找出一个nn的正方形区域,使得该区域所有数中的最大值和最小值 的差最小。

输入
第一行为3个整数,分别表示a,b,n的值第二行至第a+1行每行为b个非负整数,表示矩阵中相应位置上的数。每 行相邻两数之间用一空格分隔。 100%的数据2<=a,b<=1000,n<=a,n<=b,n<=100

输出
仅一个整数,为ab矩阵中所有“nn正方形区域中的最大整数和最小整数的差值”的最小值。

样例输入 [复制]
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 (2)20%的数据2<=a,b<=100,n<=a,n<=b,n<=10 (3)100%的数据2<=a,b<=1000,n<=a,n<=b,n<=100

简单的 单调队列 注意二维处理 不完全是 “正方形的平移”

#include<bits/stdc++.h>
using namespace std;

const int maxn=1e3+10;
int a[maxn][maxn];
int head[maxn][2],tail[maxn][2];
struct atom{
	int id,s;
}q[maxn][maxn][2],now[maxn][2];
int t[2]; 
int l[2],r[2];
signed main(){
	int n,m,N;
	scanf("%d%d%d",&n,&m,&N);
	for(int i=1;i<=n;++i){
		for(int j=1;j<=m;++j){
			scanf("%d",&a[i][j]);
		}
	}
	memset(tail,-1,sizeof tail);
	memset(head,0,sizeof head);
	int ans=2e9;
	for(int i=1;i<=n;++i){
		for(int j=1;j<=m;++j){
			while(head[j][0]<=tail[j][0]&&q[j][head[j][0]][0].id<=i-N)++head[j][0];
			while(head[j][0]<=tail[j][0]&&q[j][tail[j][0]][0].s<=a[i][j])--tail[j][0];
			q[j][++tail[j][0]][0]=(atom){i,a[i][j]};
			while(head[j][1]<=tail[j][1]&&q[j][head[j][1]][1].id<=i-N)++head[j][1];
			while(head[j][1]<=tail[j][1]&&q[j][tail[j][1]][1].s>=a[i][j])--tail[j][1];
			q[j][++tail[j][1]][1]=(atom){i,a[i][j]};
		}
		if(i>=N){
			l[0]=l[1]=0,r[0]=r[1]=-1;
			for(int j=1;j<=m;++j){
				t[0]=q[j][head[j][0]][0].s,t[1]=q[j][head[j][1]][1].s;
				while(l[0]<=r[0]&&now[l[0]][0].id<=j-N)++l[0];
				while(l[0]<=r[0]&&now[r[0]][0].s<=t[0])--r[0];
				now[++r[0]][0]=(atom){j,t[0]};
				while(l[1]<=r[1]&&now[l[1]][1].id<=j-N)++l[1];
				while(l[1]<=r[1]&&now[r[1]][1].s>=t[1])--r[1];
				now[++r[1]][1]=(atom){j,t[1]};
				if(j>=N)ans=min(ans,now[l[0]][0].s-now[l[1]][1].s);
			}
		}
		
	}
	printf("%d",ans);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值