BZOJ1047: [HAOI2007]理想的正方形

BZOJ1047: [HAOI2007]理想的正方形

Description

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

Input

  第一行为3个整数,分别表示a,b,n的值第二行至第a+1行每行为b个非负整数,表示矩阵中相应位置上的数。

每行相邻两数之间用一空格分隔。
100%的数据2<=a,b<=1000,n<=a,n<=b,n<=1000

Output

  仅一个整数,为a*b矩阵中所有“n*n正方形区域中的最大整数和最小整数的差值”的最小值。

Sample Input

5 4 2
1 2 5 6
0 17 16 0
16 17 2 1
2 10 2 1
1 2 2 2

Sample Output

1

题解Here!

一看题——这绝对是$DP$!
然后这个$flag$在$3s$之后被推翻了。
数据范围$n,m<=10^3,q<=10^2$。。。
那就直接单调队列维护每行每列,然后暴力求出最小值就好了啊!
单调队列是啥不用多说。
设$f[i][j]$表示第$i$行中$[j,j+q-1]$之间的最大值,$g[i][j]$表示第$i$行中$[j,j+q-1]$之间的最小值。
显然直接维护就好。
然后再套一个单调队列:
设$maxn[i][j]$表示$f[i][j]$中$[i,i+q-1]$行的第$j$列的最大值,$maxn[i][j]$表示$g[i][j]$中$[i,i+q-1]$行的第$j$列的最小值。
显然可以同上,直接单调队列维护就好。
然后暴力求出$maxn[i][j]-minn[i][j]$的最小值。
至于单调队列怎么实现。。。
我偷个懒,直接用$STL$——$deque$,双端队列。
附代码:
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<deque>
#define MAXN 1010
using namespace std;
deque<int> que_max,que_min;
int n,m,q,ans=2147483646;
int val[MAXN][MAXN],f[MAXN][MAXN],g[MAXN][MAXN],maxn[MAXN][MAXN],minn[MAXN][MAXN];
inline int read(){
	int date=0,w=1;char c=0;
	while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
	while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
	return date*w;
}
void work(){
	for(int j=1;j<=m-q+1;j++){
		que_max.clear();que_min.clear();
		que_max.push_back(1);que_min.push_back(1);
		for(int i=2;i<=n;i++){
			while(!que_max.empty()&&f[i][j]>=f[que_max.back()][j])que_max.pop_back();
			while(!que_min.empty()&&g[i][j]<=g[que_min.back()][j])que_min.pop_back();
			que_max.push_back(i);
			que_min.push_back(i);
			while(i-que_max.front()>=q)que_max.pop_front();
			while(i-que_min.front()>=q)que_min.pop_front();
			if(i>=q){
				maxn[i-q+1][j]=f[que_max.front()][j];
				minn[i-q+1][j]=g[que_min.front()][j];
			}
		}
	}
	for(int i=1;i<=n-q+1;i++)
	for(int j=1;j<=m-q+1;j++)
	ans=min(ans,maxn[i][j]-minn[i][j]);
	printf("%d\n",ans);
}
void init(){
	n=read();m=read();q=read();
	for(int i=1;i<=n;i++)
	for(int j=1;j<=m;j++)
	val[i][j]=read();
	for(int i=1;i<=n;i++){
		que_max.clear();que_min.clear();
		que_max.push_back(1);que_min.push_back(1);
		for(int j=2;j<=m;j++){
			while(!que_max.empty()&&val[i][j]>=val[i][que_max.back()])que_max.pop_back();
			while(!que_min.empty()&&val[i][j]<=val[i][que_min.back()])que_min.pop_back();
			que_max.push_back(j);
			que_min.push_back(j);
			while(j-que_max.front()>=q)que_max.pop_front();
			while(j-que_min.front()>=q)que_min.pop_front();
			if(j>=q){
				f[i][j-q+1]=val[i][que_max.front()];
				g[i][j-q+1]=val[i][que_min.front()];
			}
		}
	}
}
int main(){
	init();
	work();
    return 0;
}

 

posted @ 2018-10-28 20:11  符拉迪沃斯托克  阅读(200)  评论(0编辑  收藏  举报
Live2D