【BZOJ1047】[HAOI2007]理想的正方形 (倍增ST表)

[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\)

题解

刚学的二维\(ST\)表,和一维的大同小异。

\(mx[k][i][j]\)表示以\((i,j)\)作为左上角,边长为\(2^k\)的正方形内的最大值。

转移:

$mx[k][i][j]=max(max(mx[k-1][i][j],mx[k-1][i][j+(1<<(k-1))]),max(mx[k-1][i+(1<<(k-1))][j],mx[k-1][i+(1<<(k-1))][j+(1<<(k-1))])); $

最小值也是一样。

最后\(N^2\)枚举左上角端点统计答案。

code:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cctype>
#include<cmath>
#define ll long long
#define R register
#define N 1005
using namespace std;
template<typename T>inline void read(T &a){
    char c=getchar();T x=0,f=1;
    while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
    while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
    a=f*x;
}
int a,b,n,x,maxans,minans,ans=0x7fffffffLL,mx[11][N][N],mi[11][N][N];
int main(){
    read(a);read(b);read(n);
    for(R int i=1;i<=a;i++)
        for(R int j=1;j<=b;j++)
            read(x),mi[0][i][j]=mx[0][i][j]=x;
    for(R int k=1;(1<<k)<=n;k++)
        for(R int i=1;i<=a-(1<<k)+1;i++)
            for(R int j=1;j<=b-(1<<k)+1;j++)
                mi[k][i][j]=min(min(mi[k-1][i][j],mi[k-1][i][j+(1<<(k-1))]),min(mi[k-1][i+(1<<(k-1))][j],mi[k-1][i+(1<<(k-1))][j+(1<<(k-1))])),
                mx[k][i][j]=max(max(mx[k-1][i][j],mx[k-1][i][j+(1<<(k-1))]),max(mx[k-1][i+(1<<(k-1))][j],mx[k-1][i+(1<<(k-1))][j+(1<<(k-1))]));
    R int k=(int)log2(n);
    for(R int i=1;i<=a-n+1;i++){
        for(R int j=1;j<=b-n+1;j++){
            minans=0x7fffffff;maxans=-0x7fffffff;
            maxans=max(max(mx[k][i][j],mx[k][i][j+n-(1<<k)]),max(mx[k][i+n-(1<<k)][j],mx[k][i+n-(1<<k)][j+n-(1<<k)]));
            minans=min(min(mi[k][i][j],mi[k][i][j+n-(1<<k)]),min(mi[k][i+n-(1<<k)][j],mi[k][i+n-(1<<k)][j+n-(1<<k)]));
            ans=min(maxans-minans,ans);
        }
    }
    printf("%d\n",ans);	
    return 0;
}
posted @ 2018-10-23 21:33  ZAGER  阅读(240)  评论(0编辑  收藏  举报