【BZOJ1047】理想的正方形

                            1047: [HAOI2007]理想的正方形

                                              Time Limit: 10 Sec  Memory Limit: 162 MB
                                                         Submit: 4137  Solved: 2326

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

 

解析:

       先把每个位置往左 n 个单位中的最大最小值算出来(用单调队列优化),然后对于同一列维护一个单调队列,这样就能快速得到一个矩阵的最大值、最小值了。

       令f[ i ][ j ][ 0 ]表示(i , j)这个位置往左 n 个单位中最小值,f[ i ][ j ][ 1 ]为最大值,f[ i ][ j ][ 2 ]表示以(i , j)这个位置为结尾的矩形中的最小值,f[ i ][ j ][ 3 ]为最大值,详细过程见代码。

代码:

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

const int Max=1010;
const int inf=1e9;
int n,m,k,ans=inf,head,tail;
int num[Max][Max],f[Max][Max][4],p[Max<<3],q[Max<<3];

inline int get_int()
{
	int x=0,f=1;
	char c;
	for(c=getchar();(!isdigit(c))&&(c!='-');c=getchar());
	if(c=='-') {f=-1;c=getchar();}
	for(;isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+c-'0';
	return x*f;
}

inline int mn(int x,int y){return x > y ? y : x;}

inline void pre()
{
	for(int i=1;i<=n;i++)
	{
	  head = tail = 0;
	  for(int j=1;j<=n;j++) p[j]=0;
	  for(int j=1;j<=m;j++)
	  {
	  	while(head <= tail && p[head] < j-k+1) head++;
	  	while(head <= tail && num[i][j] <= num[i][p[tail]]) tail--;
	  	p[++tail] = j;
	  	f[i][j][0] = num[i][p[head]];
	  }
	  head = tail = 0;
	  for(int j=1;j<=n;j++) p[j]=0;
	  for(int j=1;j<=m;j++)
	  {
	  	while(head <= tail && p[head] < j-k+1) head++;
	  	while(head <= tail && num[i][j] >= num[i][p[tail]]) tail--;
	  	p[++tail] = j;
	  	f[i][j][1] = num[i][p[head]];
	  }
	}
}

inline void solve()
{
	for(int j=k;j<=m;j++)
	{
	  head = tail = 0;
	  for(int i=1;i<=n;i++) q[i]=0;
	  for(int i=1;i<=n;i++)
	  {
	  	while(head <= tail && q[head] < i-k+1) head++;
	  	while(head <= tail && f[i][j][0] <= f[q[tail]][j][0]) tail--;
	  	q[++tail] = i;
	  	f[i][j][2] = f[q[head]][j][0];
	  }
	  head = tail = 0;
	  for(int i=1;i<=n;i++) q[i]=0;
	  for(int i=1;i<=n;i++)
	  {
	  	while(head <= tail && q[head] < i-k+1) head++;
	  	while(head <= tail && f[i][j][1] >= f[q[tail]][j][1]) tail--;
	  	q[++tail] = i;
	  	f[i][j][3] = f[q[head]][j][1];
	  }
	}
}

int main()
{
	n=get_int(),m=get_int(),k=get_int();
	for(int i=1;i<=n;i++)
	  for(int j=1;j<=m;j++)
	  {
	    num[i][j] = get_int();
	    f[i][j][0] = f[i][j][2] = inf;
	  }

	pre();
	solve();
	for(int i=k;i<=n;i++)
	  for(int j=k;j<=m;j++) ans=mn(ans,f[i][j][3]-f[i][j][2]);
	cout<<ans<<"\n";

	return 0; 
}

猜你喜欢

转载自blog.csdn.net/m0_38083668/article/details/81431811