http://www.lydsy.com/JudgeOnline/problem.php?id=1047 http://codevs.cn/problem/1715/
题意:给定一个a*b的矩阵,找出其中的一个n*n矩阵使得矩阵中数字的极差最小,a,b<=1000。
很显然,如果我们能够求出每一个矩阵中数字的最大值和最小值,那么只要再加一个枚举就够了。
这个可以单调队列实现,但是这里由于a*b不是很大,复杂度允许带上一个log,因此我们可以考虑更简便的写法。
区间最小值很容易让人联想到RMQ。这里是二维的做法但并不是单纯的二维。
可以先考虑求出每一个1*n矩阵中数字的最大最小值,如a=3,b=3,n=2,矩阵为:
1 2 3
2 2 2
3 2 1
则每个1*n矩阵中数字的最大值为:
2 3
2 2
3 2
将上述结果也看成一个矩阵,那么我们再对上述的矩阵中的每一个n*1矩阵求值:
2 3
3 2
这个结果就是所有n*n的矩阵中数字的最大值。最小值同理。
代码:
#include<cstdio> #include<iostream> #include<cmath> #define rpt(i,l,r) for(i=l;i<=r;i++) using namespace std; int a,b,n,i,j,k,t,ans; int m[1505][1505]; int mx[1505][1505],mn[1505][1505]; int mxx[1505][1505],mnn[1505][1505]; int w[1005][10]; int p[10]; int main(){ scanf("%d%d%d",&a,&b,&n); rpt(i,1,a) rpt(j,1,b) scanf("%d",&m[i][j]); rpt(i,0,9) p[i]=1<<i; rpt(i,0,9) if(p[i]<n) t=i; rpt(i,1,a){ rpt(j,1,b) w[j][0]=m[i][j]; rpt(j,1,t) rpt(k,1,b-p[j]+1) w[k][j]=max(w[k][j-1],w[k+p[j-1]][j-1]); rpt(j,1,b-n+1) mx[i][j]=max(w[j][t],w[j+n-p[t]][t]); rpt(j,1,b) w[j][0]=m[i][j]; rpt(j,1,t) rpt(k,1,b-p[j]+1) w[k][j]=min(w[k][j-1],w[k+p[j-1]][j-1]); rpt(j,1,b-n+1) mn[i][j]=min(w[j][t],w[j+n-p[t]][t]); } rpt(i,1,b-n+1){ rpt(j,1,a) w[j][0]=mx[j][i]; rpt(j,1,t) rpt(k,1,b-p[j]+1) w[k][j]=max(w[k][j-1],w[k+p[j-1]][j-1]); rpt(j,1,a-n+1) mxx[j][i]=max(w[j][t],w[j+n-p[t]][t]); rpt(j,1,a) w[j][0]=mn[j][i]; rpt(j,1,t) rpt(k,1,b-p[j]+1) w[k][j]=min(w[k][j-1],w[k+p[j-1]][j-1]); rpt(j,1,a-n+1) mnn[j][i]=min(w[j][t],w[j+n-p[t]][t]); } ans=1<<30; rpt(i,1,a-n+1) rpt(j,1,b-n+1) if(mxx[i][j]-mnn[i][j]<ans) ans=mxx[i][j]-mnn[i][j]; printf("%d\n",ans); }