bzoj1047&CodeVS1715 理想的正方形

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

你可能感兴趣的:(bzoj1047&CodeVS1715 理想的正方形)