【BZOJ 1047】 [HAOI2007]理想的正方形 单调队列(也可以dp水)

来源:互联网 发布:a站 b站 知乎 编辑:程序博客网 时间:2024/06/08 02:59

BZOJ上面是总时间,所以这一道题在BZOJ上是可以直接用滚动数组水过去的,但是还是不推荐,不过还是写出来吧

#include<cstdio>#include<cstring>#include<iostream>#define mmax(a,b,c,d) max(a,max(b,max(c,d)))#define mmin(a,b,c,d) min(a,min(b,min(c,d)))using namespace std;int f[1024][1024],m,n,K,g[1024][1024],mat[1024][1024];int read(){    int x=0;    char c=getchar();int flag=1;    for(;c>'9'||c<'0';c=getchar()){if(c=='-')flag=-1;}    for(;c>='0'&&c<='9';c=getchar())x=x*10+c-'0';    x=x*flag;    return x;} int main(){    scanf("%d%d%d",&n,&m,&K);    for(int i=1;i<=n;i++){        for(int j=1;j<=m;j++){            mat[i][j]=read();               f[i][j]=g[i][j]=mat[i][j];        }    }    for(int k=2;k<=K;k++){        for(int i=1;i+k-1<=n;i++){            for(int j=1;j+k-1<=m;j++){                f[i][j]=mmax(mat[i][j],f[i+1][j],f[i][j+1],f[i+1][j+1]);                g[i][j]=mmin(mat[i][j],g[i+1][j],g[i][j+1],g[i+1][j+1]);            }        }    }         int ans=1e9;    for(int i=1;i+K-1<=n;i++){        for(int j=1;j+K-1<=m;j++){            ans=min(ans,f[i][j]-g[i][j]);        }    }         printf("%d",ans);    return 0;}
好了,不要只是水题就满足了,正解应该是跑两次单调队列,一次计算一行连续k的最小最大,然后再利用跑出来的一列中连续k个元素的极值来跑行就可以计算出这一个矩阵了

#include<cstdio>#include<cstring>#include<iostream>#define maxn 1020using namespace std;int n,m,k,mat[maxn][maxn],f[3][maxn][maxn];pair<int,int> q[maxn*3];void front(int pos){//0是最小值1是最大值 for(int i=1;i<=n;i++){int l=1,r=0;for(int j=1;j<=m;j++){while(l<=r&&j-q[l].first+1>k)l++;if(pos==0)while(l<=r&&q[r].second>=mat[i][j])r--;else while(l<=r&&q[r].second<=mat[i][j])r--;q[++r]=make_pair(j,mat[i][j]);f[pos][i][j]=q[l].second;}}for(int i=k;i<=m;i++){int l=1,r=0;for(int j=1;j<=n;j++){while(l<=r&&j-q[l].first+1>k)l++;if(pos==0)while(l<=r&&q[r].second>=f[pos][j][i])r--;else while(l<=r&&q[r].second<=f[pos][j][i])r--;q[++r]=make_pair(j,f[pos][j][i]);f[pos][j][i]=q[l].second;}}}int main(){scanf("%d%d%d",&n,&m,&k);for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)scanf("%d",&mat[i][j]);front(0),front(1);int ans=1e9;for(int i=k;i<=n;i++)for(int j=k;j<=m;j++)ans=min(ans,f[1][i][j]-f[0][i][j]);printf("%d",ans);return 0;}


0 0