bzoj 1047: [HAOI2007]理想的正方形 二维最值 单调队列

Description

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

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

解:

两次单调队列

1、第一次单调队列对每一列滑动窗口求最值

2、第二次用第一步得到的矩阵再次对每一行做滑动窗口我们就得到了原始矩阵的最值了

#include<stdio.h>
#include<iostream>
#include<string.h>
using namespace std;
#define ll long long
#define en '\n'
const int maxn =1e3+10;
const int inf=0x3f3f3f3f;
int a[maxn][maxn],q[maxn],A[maxn][maxn],B[maxn][maxn],AA[maxn][maxn],BB[maxn][maxn];
inline int read(){
	int x=0,f=1;  char ch=getchar();
	while(!isdigit(ch))  {if(ch=='-')  f=-1;  ch=getchar();}
	while(isdigit(ch))  {x=x*10+ch-'0';  ch=getchar();}
	return x*f;
}
int R,C,k;
signed  main()
{
#ifdef local
freopen("input2.txt","r",stdin);
#endif
#define int  register int
    cin>>R>>C>>k;
    for(int i=1;i<=R;i++){
        for(int j=1;j<=C;j++){
            a[i][j]=read();
        }//cout<<en;
    }
    int ind,indd,l,r;
        for(int j=1;j<=C;j++){
         l=1,r=0,ind=0;
        for(int i=1;i<=R;i++){
            while(l<=r and i-q[l]>=k)l+=1;
            while(l<=r and a[q[r]][j]>=a[i][j])r-=1;
            q[++r]=i;
            if(i>=k){
                A[++ind][j]=a[q[l]][j];
            }
        }
    }

     for(int j=1;j<=C;j++){
         l=1,r=0,ind=0;
        for(int i=1;i<=R;i++){
            while(l<=r and i-q[l]>=k)l+=1;
            while(l<=r and a[q[r]][j]<=a[i][j])r-=1;
            q[++r]=i;
            if(i>=k){
                B[++ind][j]=a[q[l]][j];
            }
        }
    }
    for(int i=1;i<=ind;i++){
         l=1,r=0,indd=0;
        for(int j=1;j<=C;j++){
            while(l<=r and j-q[l]>=k)l+=1;
            while(l<=r and A[i][q[r]]>=A[i][j])r-=1;
            q[++r]=j;
            if(j>=k){
                AA[i][++indd]=A[i][q[l]];
            }
        }
    }
    int ans=inf;
    for(int i=1;i<=ind;i++){
         l=1,r=0,indd=0;
        for(int j=1;j<=C;j++){
            while(l<=r and j-q[l]>=k)l+=1;
            while(l<=r and B[i][q[r]]<=B[i][j])r-=1;
            q[++r]=j;
            if(j>=k){
                BB[i][++indd]=B[i][q[l]];
                ans=min(ans,BB[i][indd]-AA[i][indd]);
            }
        }
    }
cout<<ans<<en;
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值