1. 程式人生 > >BZOJ1047: [HAOI2007]理想的正方形

BZOJ1047: [HAOI2007]理想的正方形

problems -- font true status 數據 lib .com scu

1047: [HAOI2007]理想的正方形

Time Limit: 10 Sec Memory Limit: 162 MB
Submit: 3448 Solved: 1894
[Submit][Status][Discuss]

Description

  有一個a*b的整數組成的矩陣,現請你從中找出一個n*n的正方形區域,使得該區域所有數中的最大值和最小值
的差最小。

Input

  第一行為3個整數,分別表示a,b,n的值第二行至第a+1行每行為b個非負整數,表示矩陣中相應位置上的數。每
行相鄰兩數之間用一空格分隔。
100%的數據2<=a,b<=1000,n<=a,n<=b,n<=1000

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

思路{直接二維ST表就可以了,SB的我之前以為4個ST表,打完發現一個就可以了.}

#include<bits/stdc++.h>
#define RG register
#define il inline
#define LEN (1<<(k-1))
#define Inf (1<<30)
#define N 1001
using namespace std;
int rd[10][N][N][2];
int b[N][N],n,m,len,lim;
int max(int a,int b,int c,int d){a=max(a,b);c=max(c,d),a=max(a,c);return a;}
int min(int a,int b,int c,int d){a=min(a,b),c=min(c,d),a=min(a,c);return a;}
void Modify(int x,int y,int &X){
  int Max=max(rd[lim][x][y][1],rd[lim][x+len-(1<<lim)][y][1],
          rd[lim][x][y+len-(1<<lim)][1],rd[lim][x+len-(1<<lim)][y+len-(1<<lim)][1]);
  int Min=min(rd[lim][x][y][0],rd[lim][x+len-(1<<lim)][y][0],
          rd[lim][x][y+len-(1<<lim)][0],rd[lim][x+len-(1<<lim)][y+len-(1<<lim)][0]);
  X=min(X,Max-Min);
}
int main(){
  scanf("%d%d%d",&n,&m,&len);
  for(int i=1;i<=n;++i)for(int j=1;j<=m;++j){
      scanf("%d",&b[i][j]);
      rd[0][i][j][0]=rd[0][i][j][1]=b[i][j];
    }
  for(lim=0;(1<<lim)<=len;++lim);lim--;
  for(int k=1;k<=lim;++k){
    for(int i=1;i<=n;++i)for(int j=1;j<=m;++j){
    if(i+(1<<k)<=n+1&&j+(1<<k)<=m+1){
      rd[k][i][j][1]=max(rd[k-1][i][j][1],rd[k-1][i+LEN][j][1],rd[k-1][i][j+LEN][1],rd[k-1][i+LEN][j+LEN][1]);
      rd[k][i][j][0]=min(rd[k-1][i][j][0],rd[k-1][i+LEN][j][0],rd[k-1][i][j+LEN][0],rd[k-1][i+LEN][j+LEN][0]);
      }
      }
  }int Ans=Inf;for(int i=1;i+len-1<=n;++i)for(int j=1;j+len-1<=m;++j)Modify(i,j,Ans);
  cout<<Ans;
  return 0;
}

BZOJ1047: [HAOI2007]理想的正方形