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; }