【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
題解
一道單調隊列的好題。
先對橫行進行單調隊列,然後對縱行進行依據每一行的最大最小值進行單調隊列,這樣就可以算出以一個點爲右下角的矩形的最大最小值。問題解決。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1010;
int head,tail,q[maxn];
int ans[5][maxn][maxn],c[maxn][maxn];
int main(){
	int n,m,k;
	scanf("%d%d%d",&n,&m,&k);
	for(int i=1;i<=n;i++)
	for(int j=1;j<=m;j++)
	scanf("%d",&c[i][j]);
	
	for(int i=1;i<=n;i++){
		//get max
		head=1,tail=0;	
		for(int j=1;j<=m;j++){
			while(head<=tail&&c[i][j]>=c[i][q[tail]]) tail--;
			while(head<=tail&&j-q[head]+1>k) head++;
			q[++tail]=j;
			ans[0][i][j]=c[i][q[head]];
		}
		//get min
		head=1,tail=0;
		for(int j=1;j<=m;j++){
			while(head<=tail&&c[i][j]<=c[i][q[tail]]) tail--;
			while(head<=tail&&j-q[head]+1>k) head++;
			q[++tail]=j;
			ans[1][i][j]=c[i][q[head]];
		}			
	}
	for(int j=k;j<=m;j++){
		//get ans min 
		head=1,tail=0;
		for(int i=1;i<=n;i++){
			while(head<=tail&&ans[0][i][j]>=ans[0][q[tail]][j]) tail--;
			while(head<=tail&&i-q[head]+1>k) head++;
			q[++tail]=i;
			ans[2][i][j]=ans[0][q[head]][j];
		}
		//get ans max
		head=1,tail=0;
		for(int i=1;i<=n;i++){
			while(head<=tail&&ans[1][i][j]<=ans[1][q[tail]][j]) tail--;
			while(head<=tail&&i-q[head]+1>k) head++;
			
			q[++tail]=i;
			ans[3][i][j]=ans[1][q[head]][j];
		}
	}
	int answer=2147483647;
	for(int i=k;i<=n;i++)
	for(int j=k;j<=m;j++)
	answer=min(answer,ans[2][i][j]-ans[3][i][j]);
	
	printf("%d\n",answer);

	return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章