P2216 [HAOI2007]理想的正方形

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

很显然我们可以用DP水掉这道题的大多数分。设f_max[i][j][k]表示以坐标[i,j]为右下角,边长为k的正方形的最大值,最小值同理再设一个。

因为每次处理的时候正方形边长+1,我们考虑压缩掉边长这个维度。也就是说,先预处理上边长为1的正方形(蛤蛤蛤就是输入啦),然后进行k-1次矩阵递推,得到的数据就一定是以k为边长的正方形的大小啦~

最后水过了

#include<cstdio>
#include<cstring>
#include<iostream>
#define INF 0x7777777f
using namespace std;
int n,m,k,ans=INF,mp[1010][1010],f_max[1010][1010],f_min[1010][1010];
inline int max(int x,int y){return x>y?x:y;}
inline int min(int x,int y){return x<y?x:y;}
inline int read(){
   int s=0,w=1;
   char ch=getchar();
   while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
   while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
   return s*w;
}
int main(){
    scanf("%d%d%d",&n,&m,&k);
    for(register int i=1;i<=n;++i){
        for(register int j=1;j<=m;++j){
            mp[i][j]=read();
            f_max[i][j]=mp[i][j];//init 
            f_min[i][j]=mp[i][j];
        }
    }
    for(register int l=2;l<=k;++l){
        for(register int i=n;i>=l;i--){
            for(register int j=m;j>=l;j--){
                f_max[i][j]=max(mp[i][j],max(f_max[i-1][j],max(f_max[i][j-1],f_max[i-1][j-1])));
                f_min[i][j]=min(mp[i][j],min(f_min[i-1][j],min(f_min[i][j-1],f_min[i-1][j-1])));
            }
        }       
    }
    for(register int i=k;i<=n;++i){
        for(register int j=k;j<=m;++j){
            ans=min(ans,f_max[i][j]-f_min[i][j]);
        }
    }
    printf("%d\n",ans);
    return 0;
} 
View Code

 

posted @ 2020-04-12 19:59  INFP  阅读(159)  评论(0编辑  收藏  举报