bzoj 1047: [HAOI2007]理想的正方形【单调队列】

没有复杂结构甚至不长但是写起来就很想死的代码类型

原理非常简单,就是用先用单调队列处理出mn1[i][j]表示i行的j到j+k-1列的最小值,mx1[i][j]表示i行的j到j+k-1列的最大值

然后就变成求单列最大最小值,用上面同样的方法处理出对于列的mn2mx2即可

#include<iostream>
#include<cstdio>
using namespace std;
const int N=1005;
int n,m,k,a[N][N],mn1[N][N],mx1[N][N],mn2[N][N],mx2[N][N],ans=1e9,q1[N],l1,r1,q2[N],l2,r2;
int read()
{
    int r=0,f=1;
    char p=getchar();
    while(p>‘9‘||p<‘0‘)
    {
        if(p==‘-‘)
            f=-1;
        p=getchar();
    }
    while(p>=‘0‘&&p<=‘9‘)
    {
        r=r*10+p-48;
        p=getchar();
    }
    return r*f;
}
int main()
{
    n=read(),m=read(),k=read();
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            a[i][j]=read();
    for(int i=1;i<=n;i++)
        {
            l2=r2=l1=r1=q2[1]=q1[1]=1;
            for(int j=2;j<=m;j++)
                {
                    while(a[i][j]>=a[i][q2[r2]]&&l2<=r2)
                        r2--;
                    while(a[i][j]<=a[i][q1[r1]]&&l1<=r1)
                        r1--;
                    q2[++r2]=j;q1[++r1]=j;
                    while(j-q2[l2]>=k)
                        l2++;
                    while(j-q1[l1]>=k)
                        l1++;
                    if(j>=k)
                        mx1[i][j-k+1]=a[i][q2[l2]],mn1[i][j-k+1]=a[i][q1[l1]];
                }
        }
    for (int j=1;j<=m-k+1;j++)
        {
            l2=r2=l1=r1=q2[1]=q1[1]=1;
            for(int i=2;i<=n;i++)
                {
                    while(mx1[i][j]>=mx1[q2[r2]][j]&&l2<=r2)
                        r2--;
                    while(mn1[i][j]<=mn1[q1[r1]][j]&&l1<=r1)
                        r1--;
                    q2[++r2]=i;q1[++r1]=i;
                    while(i-q2[l2]>=k)
                        l2++;
                    while(i-q1[l1]>=k)
                        l1++;
                    if(i>=k)
                        mx2[i-k+1][j]=mx1[q2[l2]][j],mn2[i-k+1][j]=mn1[q1[l1]][j];
                }
        }
    for(int i=1;i<=n-k+1;i++)
        for(int j=1;j<=m-k+1;j++)
            ans=min(ans,mx2[i][j]-mn2[i][j]);
    printf("%d\n",ans);
    return 0;
}

原文地址:https://www.cnblogs.com/lokiii/p/9410877.html

时间: 2024-10-17 04:49:18

bzoj 1047: [HAOI2007]理想的正方形【单调队列】的相关文章

BZOJ 1047 HAOI2007 理想的正方形 单调队列

题目大意:给定一个a*b的矩阵,求一个n*n的子矩阵,使矩阵中的最大值与最小值之差最小 对于每行维护一个单调递减的队列.再弄一个竖着的队列.维护n个格子之内的最大值就可以 两遍统计出最大值和最小值 然后得到ans就可以 #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define M 1010 using namespace std; struct abcd

BZOJ 1047 [HAOI2007]理想的正方形

[看了题解才会做 这是一个典型的二维滑动窗口问题~ 二维滑动窗口问题的处理方法可以类比一维滑动窗口的处理方法 首先将矩阵分解成B个列,对这B个列分别用单调队列维护一个长度为N的一维滑动窗口.记录colmax[i][j]为第j列第i行的元素(即第j个列的第i个元素)到第j列第i-N+1的元素(即第j个列的第i-N+1个元素)的最大值.这个用单调队列随便维护一下就好啦~ 然后将矩阵分解成A个行,对这A个行再分别用单调队列维护一个长度为N的一维滑动窗口.记录rowmax[i][j]为colmax[i]

HAOI2007 理想的正方形 单调队列

单调队列 by   GeneralLiu 滑动窗口是比较裸的单调队列 理想的正方形   就拔高了一个层次(多了一维) 有一个a*b的整数组成的矩阵 现请你从中找出一个n*n的正方形区域 使得该区域所有数中的最大值和最小值的差最小 只写MAX了,MIN一个道理,懒 不写了 先横着跑单调队列 维护许多长度为 n 的 横着的MAX 存在数组 map1[][] 中 再对数组 map1[][] 竖着跑单调队列 就维护了 许多 n*n 的 矩阵的MAX MIN同理 在竖着跑单调队列时 顺便MAX 与 MIN

P2216 [HAOI2007]理想的正方形 - 单调队列

这种矩形问题常用单调队列优化枚举(通过贪心取最优降低了一个维度的枚举) 推荐这道题也要做一做:[ZJOI2007]棋盘制作 单调队列的空间记得开大点! 反正内存够用 注意,这题正方形边长是固定的! 暴力算法是枚举上边界所在的行,左边界所在的列,通过这两个个信息确定一个正方形,然后预处理出一行中从第i个点到i+n个点的最值,再扫一遍这个正方形的行,复杂度是N^3 预处理的时候,复杂度也是N^3...考虑用单调队列来维护,枚举到一行,看做一个序列,求长度为n的区间最值,就是一个滑动窗口,如果不大明白

[BZOJ1047] [HAOI2007] 理想的正方形 (单调队列)

Description 有一个a*b的整数组成的矩阵,现请你从中找出一个n*n的正方形区域,使得该区域所有数中的最大值和最小值的差最小. Input 第一行为3个整数,分别表示a,b,n的值第二行至第a+1行每行为b个非负整数,表示矩阵中相应位置上的数.每行相邻两数之间用一空格分隔.100%的数据2<=a,b<=1000,n<=a,n<=b,n<=100 Output 仅一个整数,为a*b矩阵中所有“n*n正方形区域中的最大整数和最小整数的差值”的最小值. Sample In

[HAOI2007]理想的正方形 单调队列 暴力

Code: #include<cstdio> #include<queue> #include<algorithm> using namespace std; #define maxn 1002 #define ll long long #define inf 100000000000 int minv[maxn][maxn], maxv[maxn][maxn]; struct Node{ ll val; int pos; Node(ll val=0,int pos=0

【BZOJ】1047: [HAOI2007]理想的正方形(单调队列/~二维rmq+树状数组套树状数组)

http://www.lydsy.com/JudgeOnline/problem.php?id=1047 树状数组套树状数组真心没用QAQ....首先它不能修改..而不修改的可以用单调队列做掉,而且更快,只有O(n^2).而这货是n^2log^2n的建树...虽然查询是log^2n...但是建树那里就tle了.. 那么说题解... 先orz下,好神.. 我怎么没想到单调队列orz 首先我们维护 行 的单调队列,更新每个点在 列 距离内的最小and最大的值 然后我们维护 列 的单调队列,更新每个点

1047: [HAOI2007]理想的正方形——二维单调队列

http://www.lydsy.com/JudgeOnline/problem.php?id=1047 对每一行维护一个单调队列,保存在lmin[][],lmax[][] 然后对每一列维护一个单调队列,最后n*n枚举 #include <iostream> #include <cstring> #include <cstdio> #include <algorithm> #define clr(a,b) memset(a,b,sizeof(a)) cons

BZOJ 1047 理想的正方形(单调队列)

刚开始用二维RMQ直接给超内存了... 用单调队列可以做到O(n^2)的复杂度.具体是先把每行用单调队列处理一下.再把处理后的用列单调队列处理下. # include <cstdio> # include <cstring> # include <cstdlib> # include <iostream> # include <vector> # include <queue> # include <stack> # in