BZOJ1047 - [HAOI2007]理想的正方形

原题链接

题意简述

有一个由n×m个整数组成的矩阵,现请你从中找出一个k×k的方阵,使得该方阵所有数中的最大值和最小值的差最小。

分析

首先处理出c1[i][j]表示max{a[i][j..(j+k1)]}c2[i][j]表示min{a[i][j..(j+k1)]}。也就是从(i,j)向右连续k个数中的最值。
然后以(i,j)为左上角的k×k方阵中的最大值就是max{c1[i..(i+k1)][j]},最小值就是min{c2[i..(i+k1)][j]}。因为(i,j)向右k个数加上(i+1,j)向右k个数加上…加上(i+k1,j)向右k个数就是以(i,j)为左上角的k×k方阵。所有最大值与最小值的差中的最小值就是答案。
以上都可以通过单调队列实现。
总时间复杂度O(nm)

实现

开两个单调队列,一个递增,一个递减。

代码

//[HAOI2007]理想的正方形
#include <cstdio>
#include <algorithm>
using namespace std;
int const N=1e3+10;
int const INF=0x7FFFFFFF;
int n,m,k,a[N][N];
int c[2][N][N];
struct queue
{
    int op,cl,type;
    struct ele{int x,y,val;} qu[N];
    void clear() {op=1,cl=0;}
    void push(int x,int y,int val)
    {
        if(type==0) while(qu[cl].val<=val && cl>=op) cl--;
        else while(qu[cl].val>=val && cl>=op) cl--;
        cl++; qu[cl].x=x,qu[cl].y=y,qu[cl].val=val;
    }
    int topX() {return qu[op].x;}
    int topY() {return qu[op].y;}
    int topV() {return qu[op].val;}

}q[2];
void push1(int x,int y) {q[0].push(x,y,a[x][y]); q[1].push(x,y,a[x][y]);}
void push2(int x,int y) {q[0].push(x,y,c[0][x][y]); q[1].push(x,y,c[1][x][y]);}
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",&a[i][j]);
    q[0].type=0; q[1].type=1;
    for(int i=1;i<=n;i++)
    {
        q[0].clear(); q[1].clear();
        for(int j=1;j<=k;j++) push1(i,j);
        c[0][i][1]=q[0].topV();
        c[1][i][1]=q[1].topV();
        for(int j=2;j<=m-k+1;j++)  
        {
            if(q[0].topY()<j) q[0].op++;
            if(q[1].topY()<j) q[1].op++;
            push1(i,j+k-1);
            c[0][i][j]=q[0].topV();
            c[1][i][j]=q[1].topV();
        }
    }
    int ans=INF;
    for(int j=1;j<=m-k+1;j++)
    {
        q[0].clear(); q[1].clear();
        for(int i=1;i<=k;i++) push2(i,j);
        ans=min(ans,q[0].topV()-q[1].topV());
        for(int i=2;i<=n-k+1;i++)
        {
            if(q[0].topX()<i) q[0].op++;
            if(q[1].topX()<i) q[1].op++;
            push2(i+k-1,j);
            ans=min(ans,q[0].topV()-q[1].topV());
        }
    }
    printf("%d",ans);
    return 0;
}

注意

代码可能很难写的简洁…我尽力了

posted @ 2017-11-03 10:12  VisJiao  阅读(147)  评论(0编辑  收藏  举报