P2216 [HAOI2007]理想的正方形(框正方形使数值差最小 单调队列)

原题: https://www.luogu.org/problemnew/show/P2216

题意:

给出n*m的数字矩阵,框出一个c*c正方形使最大值-最小值最小。

解析:

这题昨晚睡前想了一下,只要能快速处理一个区间的最值就可以暴力了,管他怎么dp。线段树有感觉大材小用了感觉。

想到用优先队列可以快速得出1*c那么一条的最值,又想到了一个正方形是c条1*c组成的,那么问题就解决啦。

结果想完这题后就睡不着了,作孽啊~


早上起来敲了一发优先队列TLE了

#include
using namespace std;

struct node{
    int v,idx;
    node(){}
    node(int v,int idx):v(v),idx(idx){}
    bool operator <(const node &r)const{
        return v<r.v;
    }
    bool operator >(const node &r)const{
        return v>r.v;
    }
};
priority_queue<node>Qmax;
priority_queue<node,vector<node>,greater<node> >Qmin;

int a[1009][1009];
int minn[1009][1009];
int maxx[1009][1009];
int main(){
    int n,m,c;scanf("%d%d%d",&n,&m,&c);
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            scanf("%d",a[i]+j);
        }
    }
    for(int j=1;j<=m;j++){
        while(!Qmin.empty())Qmin.pop();
        while(!Qmax.empty())Qmax.pop();
        for(int i=1;i<c;i++)Qmin.push(node(a[i][j],i)),Qmax.push(node(a[i][j],i));
        for(int i=c;i<=n;i++){
            Qmin.push(node(a[i][j],i)),Qmax.push(node(a[i][j],i));
            while(Qmin.top().idx<i-c+1)Qmin.pop();
            while(Qmax.top().idx<i-c+1)Qmax.pop();
            minn[i-c+1][j]=Qmin.top().v;
            maxx[i-c+1][j]=Qmax.top().v;
        }
    }
    int ans=0x3f3f3f3f;
    for(int i=1;i<=n-c+1;i++){
        while(!Qmin.empty())Qmin.pop();
        while(!Qmax.empty())Qmax.pop();
        for(int j=1;j<c;j++)Qmin.push(node(minn[i][j],j)),Qmax.push(node(maxx[i][j],j));
        for(int j=c;j<=m;j++){
            Qmin.push(node(minn[i][j],j)),Qmax.push(node(maxx[i][j],j));
            while(Qmin.top().idx<j-c+1)Qmin.pop();
            while(Qmax.top().idx<j-c+1)Qmax.pop();
            ans=min(ans,Qmax.top().v-Qmin.top().v);
        }
    }
    printf("%d\n",ans);
}

再想了一下,其实单调队列就可以维护,和单调栈一样的做法,只是多了一个bottom,最大值存在Q[bottom]罢了(bottom初值为1)。

#include
using namespace std;
#define DEBU
#define debug(i) printf("# %d\n",i);

int a[1009][1009];
int minn[1009][1009];
int maxx[1009][1009];
int qmin[1009],qmax[1009],top1,bottom1,top2,bottom2;
int main(){
    int n,m,c;scanf("%d%d%d",&n,&m,&c);

    //int n=1000,m=1000,c=100;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            scanf("%d",a[i]+j);
            //a[i][j]=rand();
        }
    }
    for(int j=1;j<=m;j++){
        top1=top2=0;
        bottom1=bottom2=1;
        for(int i=1;i<c;i++){
            while(top1>=bottom1&&a[i][j]<a[qmin[top1]][j])top1--;
            qmin[++top1]=i;
            while(top2>=bottom2&&a[i][j]>a[qmax[top2]][j])top2--;
            qmax[++top2]=i;
        }
        for(int i=c;i<=n;i++){
            while(top1>=bottom1&&a[i][j]<a[qmin[top1]][j])top1--;
            qmin[++top1]=i;
            while(top2>=bottom2&&a[i][j]>a[qmax[top2]][j])top2--;
            qmax[++top2]=i;
            while(qmin[bottom1]<i-c+1)bottom1++;
            while(qmax[bottom2]<i-c+1)bottom2++;
            minn[i-c+1][j]=a[qmin[bottom1]][j];
            maxx[i-c+1][j]=a[qmax[bottom2]][j];
        }
    }
#ifdef DEBUG
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            printf("(%d %d) ",minn[i][j],maxx[i][j]);
        }
        printf("\n");
    }
#endif // DEBUG

    int ans=0x3f3f3f3f;
    for(int i=1;i<=n-c+1;i++){
        top1=top2=0;
        bottom1=bottom2=1;
        for(int j=1;j<c;j++){
            while(top1>=bottom1&&minn[i][j]<minn[i][qmin[top1]])top1--;
            qmin[++top1]=j;
            while(top2>=bottom2&&maxx[i][j]>maxx[i][qmax[top2]])top2--;
            qmax[++top2]=j;
        }
        for(int j=c;j<=m;j++){
            while(top1>=bottom1&&minn[i][j]<minn[i][qmin[top1]])top1--;
            qmin[++top1]=j;
            while(top2>=bottom2&&maxx[i][j]>maxx[i][qmax[top2]])top2--;
            qmax[++top2]=j;
            while(qmin[bottom1]<j-c+1)bottom1++;
            while(qmax[bottom2]<j-c+1)bottom2++;
            ans=min(ans,maxx[i][qmax[bottom2]]-minn[i][qmin[bottom1]]);
        }
    }
    printf("%d\n",ans);
}


去看了别人的题解,ST表也可以做,这个原理是一样的,用ST表处理一条的最值,再用ST表处理多条之间的最值。
所以说这是道水题了。。。

你可能感兴趣的:(其他算法)