P2216 [HAOI2007]理想的正方形 单调队列

  

题目描述

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

输入格式

第一行为3个整数,分别表示a,b,n的值

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

输出格式

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

输入输出样例

输入 #1复制
5 4 2
1 2 5 6
0 17 16 0
16 17 2 1
2 10 2 1
1 2 2 2
输出 #1复制
1

说明/提示

问题规模

(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<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define repp(i,a,b) for(int i=(a);i>=(b);--i)
#define ll long long
#define see(x) (cerr<<(#x)<<'='<<(x)<<endl)
#define inf 0x3f3f3f3f
#define CLR(A,v)  memset(A,v,sizeof A)
//
const int N=1000+10;
int mp[N][N],maxx[N][N],minn[N][N],n,m,k;
int de[N],de2[N];

int main()
{
    cin>>n>>m>>k;
    rep(i,1,n)rep(j,1,m)scanf("%d",&mp[i][j]),maxx[i][j]=0,minn[i][j]=0;

    rep(i,1,n)
    {
        int l=1,r=0,l2=1,r2=0;
        rep(j,1,k)
        {
            while(l<=r&&mp[i][de[r]]>=mp[i][j])r--;
            de[++r]=j;
            while(l2<=r2&&mp[i][de2[r2]]<=mp[i][j])r2--;
            de2[++r2]=j;
        }
        minn[i][1]=mp[i][de[l]];
        maxx[i][1]=mp[i][de2[l]];

        rep(j,2,m-k+1)
        {
            while(l<=r&&mp[i][de[r]]>=mp[i][j+k-1])r--;
            while(l2<=r2&&mp[i][de2[r2]]<=mp[i][j+k-1])r2--;
            de[++r]=j+k-1;
            de2[++r2]=j+k-1;
            if(l<=r&&de[l]<j)l++;
            if(l2<=r2&&de2[l2]<j)l2++;
            minn[i][j]=mp[i][de[l]];
            maxx[i][j]=mp[i][de2[l2]];
        }
    }
    rep(j,1,m)
    {
        int l=1,r=0,l2=1,r2=0;
        rep(i,1,k)
        {
            while(l<=r&&minn[de[r]][j]>=minn[i][j])r--;
            de[++r]=i;
            while(l2<=r2&&maxx[de2[r2]][j]<=maxx[i][j])r2--;
            de2[++r2]=i;
        }
        minn[1][j]=minn[de[l]][j];
        maxx[1][j]=maxx[de2[l2]][j];

        rep(i,2,n-k+1)
        {
            while(l<=r&&minn[de[r]][j]>=minn[i+k-1][j])r--;
            while(l2<=r2&&maxx[de2[r2]][j]<=maxx[i+k-1][j])r2--;
            de[++r]=i+k-1;
            de2[++r2]=i+k-1;
            if(l<=r&&de[l]<i)l++;
            if(l2<=r2&&de2[l2]<i)l2++;
            minn[i][j]=minn[de[l]][j];
            maxx[i][j]=maxx[de2[l2]][j];
        }
    }
    int ans=inf;
    rep(i,1,n-k+1)
    rep(j,1,m-k+1)
    ans=min(ans,maxx[i][j]-minn[i][j]);
    cout<<ans;

    return 0;
}
View Code

 

 

 

 

转载于:https://www.cnblogs.com/bxd123/p/11393926.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值