Evanyou Blog 彩带

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

 

Solution:

  本题单调队列(当然也可以倍增)。

  如果是一维的情况,就是经典的滑动窗口求极值的问题了。

  考虑二维的情况,我们在每行都跑下单调队列,处理出$(i,j)$往左$n$个位置的极值。

  再在处理出的$(i,j)$的行极值上,以每列的情况跑下单调队列,就能处理出$(i,j)$为右下角所在的$n*n$矩形内的极值了。

代码:

/*Code by 520 -- 9.19*/
#include<bits/stdc++.h>
#define il inline
#define ll long long
#define RE register
#define For(i,a,b) for(RE int (i)=(a);(i)<=(b);(i)++)
#define Bor(i,a,b) for(RE int (i)=(b);(i)>=(a);(i)--)
using namespace std;
const int N=1005;
int a,b,n,l1,r1,l2,r2,mp[N][N],x[N][N][2],y[N][N][2],q[N][2],ans=0x7fffffff;

int gi(){
    int a=0;char x=getchar();bool f=0;
    while((x<'0'||x>'9')&&x!='-') x=getchar();
    if(x=='-') x=getchar(),f=1;
    while(x>='0'&&x<='9') a=(a<<3)+(a<<1)+(x^48),x=getchar();
    return f?-a:a;
}

int main(){
    a=gi(),b=gi(),n=gi();
    For(i,1,a) For(j,1,b) mp[i][j]=gi();
    For(i,1,a) {
        l1=1,r1=0,l2=1,r2=0;
        For(j,1,b) {
            while(l1<=r1&&mp[i][q[r1][0]]>=mp[i][j]) r1--;
            q[++r1][0]=j;
            while(l2<=r2&&mp[i][q[r2][1]]<=mp[i][j]) r2--;
            q[++r2][1]=j;
            while(q[l1][0]<=j-n) l1++;
            while(q[l2][1]<=j-n) l2++;
            if(j>=n) x[i][j][0]=mp[i][q[l1][0]],x[i][j][1]=mp[i][q[l2][1]];
        }
    }
    For(j,n,b) {
        l1=1,r1=0,l2=1,r2=0;
        For(i,1,a) {
            while(l1<=r1&&x[q[r1][0]][j][0]>=x[i][j][0]) r1--;
            q[++r1][0]=i;
            while(l2<=r2&&x[q[r2][1]][j][1]<=x[i][j][1]) r2--;
            q[++r2][1]=i;
            while(q[l1][0]<=i-n) l1++;
            while(q[l2][1]<=i-n) l2++;
            if(i>=n) ans=min(ans,x[q[l2][1]][j][1]-x[q[l1][0]][j][0]);
        }
    }
    cout<<ans;
    return 0;    
}

 

posted @ 2018-09-20 09:53  five20  阅读(200)  评论(0编辑  收藏  举报
Live2D