博客园 首页 私信博主 显示目录 隐藏目录 管理 动画

bzoj:1047: [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
 
 
 
单调队列维护(i,j)在这一行往前n个位置的最大值和最小值,最后再单调队列统计一下就好啦
#include<cstdio>
#include<algorithm>
using namespace std;
 
int a,b,n,map[1001][1001],la[1001][1001],li[1001][1001],q[1001],num[1001],w[1001],nm[1001],fi,len,fw,lw,ans=1000000001,o,p;
inline int read(){
    p=0;o=getchar();
    while(o<'0'||o>'9') o=getchar();
    while(o>='0'&&o<='9') p=p*10+o-48,o=getchar();
    return p;
}
inline int max(int x,int y){return x>y?x:y;}
int main(){
    register int i,j;
    a=read();b=read();n=read();
    for (i=1;i<=a;i++)
    for (j=1;j<=b;j++) map[i][j]=read();
    for (i=1;i<=a;i++){
        fi=1;len=0;
        for (j=1;j<=b;j++){
            while ((len>=fi)&&(q[len]<=map[i][j])) len--;
            q[++len]=map[i][j];
            num[len]=j;
            while(num[fi]<=j-n) fi++;
            la[i][j]=q[fi];
        }
    }
    for (i=1;i<=a;i++){
        fi=1;len=0;
        for (j=1;j<=b;j++){
            while ((len>=fi)&&(q[len]>=map[i][j])) len--;
            q[++len]=map[i][j];
            num[len]=j;
            while(num[fi]<=j-n) fi++;
            li[i][j]=q[fi];
        }
    }
    for (j=n;j<=b;j++){
        fi=fw=1;len=lw=0;
        for (i=1;i<=a;i++){
            while((len>=fi)&&(q[len]<=la[i][j])) len--;
            q[++len]=la[i][j];
            num[len]=i;
            while(num[fi]<=i-n) fi++;
            while((lw>=fw)&&(w[lw]>=li[i][j])) lw--;
            w[++lw]=li[i][j];
            nm[lw]=i;
            while(nm[fw]<=i-n) fw++;
            if (i>=n) ans=min(q[fi]-w[fw],ans);
        }
    }
    printf("%d\n",ans);
}

 

posted @ 2016-01-11 14:20  swm_sxt  阅读(185)  评论(0编辑  收藏  举报