[HAOI2007]理想的正方形

标签: 单调队列


题目描述

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

输入格式:

第一行为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

分析

  先枚举正方形所在的行,确定行之后,用滑动窗口分别求出窗口中的最大和最小值.

代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
const int maxn=1050;
const int inf=0x3f3f3f3f;
int s[maxn][maxn],a,b,n;
struct Queue
{
	int q[maxn],t,h;
	Queue(){
		t=0,h=1;
	}
	void push(int x,int y,int f=1){
		while(t-h+1>=1&&s[q[t]][y]*f>=s[x][y]*f) t--;
		q[++t]=x;
	}
	void pop(int x){
		while(t-h+1>=1&&q[h]<x) h++;
	}
	int top(){
		return q[h];
	}
}m[maxn],M[maxn];

int main(int argc, char const *argv[])
{
	scanf("%d%d%d", &a,&b,&n);
	for (int i = 0; i < a; ++i)
	{
		for (int j = 0; j < b; ++j)
		{
			scanf("%d", &s[i][j]);
		}
	}
	int ans=inf;
	for (int i = 0; i+n <= a; ++i)
	{
		if(i==0)
			for (int j = 0; j < b; ++j)
			{
				for (int k = 0; k < n; ++k)
				{
					m[j].push(k,j);
					M[j].push(k,j,-1);
				}
			}
		else
			for (int j = 0; j < b; ++j)
			{
				m[j].pop(i),m[j].push(i+n-1,j);
				M[j].pop(i),M[j].push(i+n-1,j,-1);
			}
		int h=1,t=0,X[maxn],Y[maxn];
		int hh=1,tt=0,XX[maxn],YY[maxn];
		for (int j = 0; j+n <= b; ++j)
		{
			if(j==0){
				for (int k = j; k < j+n; ++k)
				{
					int x=m[k].top();
					while(t-h+1>=1&&s[X[t]][Y[t]]>=s[x][k]) t--;
					X[++t]=x,Y[t]=k;

					x=M[k].top();
					while(tt-hh+1>=1&&s[XX[tt]][YY[tt]]<=s[x][k]) tt--;
					XX[++tt]=x,YY[tt]=k;
				}
			}
			else{
				int x=m[j+n-1].top();
				while(t-h+1>=1&&s[X[t]][Y[t]]>=s[x][j+n-1]) t--;
				X[++t]=x,Y[t]=j+n-1;

				x=M[j+n-1].top();
				while(tt-hh+1>=1&&s[XX[tt]][YY[tt]]<=s[x][j+n-1]) tt--;
				XX[++tt]=x,YY[tt]=j+n-1;
			}
			while(Y[h]<j) h++;
			while(YY[hh]<j) hh++;
			ans=min(ans,s[XX[hh]][YY[hh]]-s[X[h]][Y[h]]);
		}
	}
	printf("%d\n", ans);
	return 0;
}
posted @ 2018-05-17 13:18  sciorz  阅读(157)  评论(0编辑  收藏  举报