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

Description

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

Input

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

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

HINT

问题规模

(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>
#define N 1010
using namespace std;
struct use{int p,v;}q1[N],q2[N],qmx[N][N],qmn[N][N];
int n,m,k,a[N][N],l1,r1,l2,r2,lmx[N],rmx[N],lmn[N],rmn[N],ans(999999999);
void push(int x,int p,int i){
  while(lmx[i]<=rmx[i]&&p-qmx[i][lmx[i]].p>=k) lmx[i]++;
  while(lmn[i]<=rmn[i]&&p-qmn[i][lmn[i]].p>=k) lmn[i]++;  
  while(lmx[i]<=rmx[i]&&x>=qmx[i][rmx[i]].v) rmx[i]--;
  while(lmn[i]<=rmn[i]&&x<=qmn[i][rmn[i]].v) rmn[i]--;
  qmx[i][++rmx[i]].v=qmn[i][++rmn[i]].v=x;qmx[i][rmx[i]].p=qmn[i][rmn[i]].p=p;
}
void push2(int mx,int mn,int p){
  while(l1<=r1&&p-q1[l1].p>=k) l1++;
  while(l2<=r2&&p-q2[l2].p>=k) l2++;
  while(l1<=r1&&mx>=q1[r1].v) r1--;
  while(l2<=r2&&mn<=q2[r2].v) r2--;
  q1[++r1].v=mx;q2[++r2].v=mn;q1[r1].p=q2[r2].p=p;
}
int main(){ 
  scanf("%d%d%d",&n,&m,&k);
  for (int i=1;i<=n;i++)
   for (int j=1;j<=m;j++)
     scanf("%d",&a[i][j]);
  for (int i=1;i<=m;i++) lmx[i]=lmn[i]=1;
  for (int i=1;i<=m;i++)
   for (int j=1;j<=k;j++)push(a[j][i],j,i);
  for (int i=k;i<=n;i++){
   l1=l2=1;r1=r2=0;
   if (i!=k) for (int j=1;j<=m;j++) push(a[i][j],i,j);
   for (int j=1;j<=k;j++) push2(qmx[j][lmx[j]].v,qmn[j][lmn[j]].v,j);
   ans=min(ans,q1[l1].v-q2[l2].v);
   for (int j=k+1;j<=m;j++){
     push2(qmx[j][lmx[j]].v,qmn[j][lmn[j]].v,j);ans=min(ans,q1[l1].v-q2[l2].v);
    } 
  } 
  cout<<ans<<endl;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值