理想的正方形

  【题目描述】

  一个a*b的矩阵,从中取一个n*n的子矩阵,使所选矩阵中的最大数与最小数的差最小。

  思路:

  二维的滑动窗口

  对于每行:用一个单调队列维护,算出每个长度为n的区间的最大值和最小值,分别存在两个数组fmin和fmax中,fmax[i][j]表示第i行区间[j,j+n-1]的最大值。

  对于每列:用一个单调队列维护,算出fmax和fmin数组中纵列每个长度为n的区间的最大值和最小值,分别存在两个数组ffmin和ffmax中,

ffmax[i][j]表示以(i,j)为左上端点的大小为n*n的矩阵中的最大值。

  扫一遍ffmax[1~a-n+1][1~b-n+1]和ffmin[1~a-n+1][1~b-n+1]的差,得出ans。

  单调队列原理:

  以维护最大值为例:

  对于每个新加入区间的值,显而易见的是:对于向右移动的“窗口”,即当前长度为n的区间中,若存在data[q[i]]比data[q[j]]大且q[i]>q[j](q[i]表示队列中的第i个元素的编号,data[i]表示编号为i的元素的值),则可以保证q[j]在以后的区间取最大值时是不会产生影响的,我们便可以将q[j]删除,从而得到更加优秀的时间复杂度,所以,当一个新的值入队时,便可以将在其前面入队且值比它小的元素删除。 我们便可以发现可以用一个单调队列维护。 当然,对于不在当前区间内的“老”元素,要把它从队列中删除。

贴C++代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int a,b,n;
int g[][],fmin[][],fmax[][],ffmin[][],ffmax[][],queue[],head,tail,i,j,ans=0x7fffffff;
int main()
{
scanf("%d%d%d",&a,&b,&n);
for(i=;i<=a;i++)
for(j=;j<=b;j++)
scanf("%d",&g[i][j]);
for(i=;i<=a;i++) //枚举每行 单调递减求区间最大值
{
head=;tail=;
memset(queue,,sizeof(queue));
for(j=;j<n;j++)
{
while(tail>&&g[i][queue[tail]]<g[i][j]) tail--;
queue[++tail]=j;
}
for(j=n;j<=b;j++)
{
while(tail>=head&&g[i][queue[tail]]<g[i][j]) tail--;
queue[++tail]=j;
if(queue[head]<j-n+) head++;
fmax[i][j-n+]=g[i][queue[head]];
}
}
for(i=;i<=a;i++) //枚举每行 单调递增求区间最小值
{
head=;tail=;
memset(queue,,sizeof(queue));
for(j=;j<n;j++)
{
while(tail>&&g[i][queue[tail]]>g[i][j]) tail--;
queue[++tail]=j;
}
for(j=n;j<=b;j++)
{
while(tail>=head&&g[i][queue[tail]]>g[i][j]) tail--;
queue[++tail]=j;
if(queue[head]<j-n+) head++;
fmin[i][j-n+]=g[i][queue[head]];
}
}
for(i=;i<=b-n+;i++) //枚举每列 单调递减求区间最大值
{
head=;tail=;
memset(queue,,sizeof(queue));
for(j=;j<n;j++)
{
while(tail>&&fmax[queue[tail]][i]<fmax[j][i]) tail--;
queue[++tail]=j;
}
for(j=n;j<=a;j++)
{
while(tail>=head&&fmax[queue[tail]][i]<fmax[j][i]) tail--;
queue[++tail]=j;
if(queue[head]<j-n+) head++;
ffmax[j-n+][i]=fmax[queue[head]][i];
}
}
for(i=;i<=b-n+;i++) //枚举每列 单调递增求区间最小值
{
head=;tail=;
memset(queue,,sizeof(queue));
for(j=;j<n;j++)
{
while(tail>&&fmin[queue[tail]][i]>fmin[j][i]) tail--;
queue[++tail]=j;
}
for(j=n;j<=a;j++)
{
while(tail>=head&&fmin[queue[tail]][i]>fmin[j][i]) tail--;
queue[++tail]=j;
if(queue[head]<j-n+) head++;
ffmin[j-n+][i]=fmin[queue[head]][i];
}
}
for(i=;i<=a-n+;i++)
for(j=;j<=b-n+;j++)
ans=min(ans,ffmax[i][j]-ffmin[i][j]);
printf("%d\n",ans);
return ;
}

【洛谷P2216】[HAOI2007]理想的正方形的更多相关文章

  1. 洛谷 P2216 [HAOI2007]理想的正方形

    P2216 [HAOI2007]理想的正方形 题目描述 有一个a*b的整数组成的矩阵,现请你从中找出一个n*n的正方形区域,使得该区域所有数中的最大值和最小值的差最小. 输入输出格式 输入格式: 第一 ...

  2. 洛谷P2216: [HAOI2007]理想的正方形 单调队列优化DP

    洛谷P2216 )逼着自己写DP 题意: 给定一个带有数字的矩阵,找出一个大小为n*n的矩阵,这个矩阵中最大值减最小值最小. 思路: 先处理出每一行每个格子到前面n个格子中的最大值和最小值.然后对每一 ...

  3. 洛谷 P2216 [HAOI2007]理想的正方形 || 二维RMQ的单调队列

    题目 这个题的算法核心就是求出以i,j为左上角,边长为n的矩阵中最小值和最大值.最小和最大值的求法类似. 单调队列做法: 以最小值为例: q1[i][j]表示第i行上,从j列开始的n列的最小值.$q1 ...

  4. 洛谷P2216 HAOI2007 理想的正方形 (单调队列)

    题目就是要求在n*m的矩形中找出一个k*k的正方形(理想正方形),使得这个正方形内最值之差最小(就是要维护最大值和最小值),显然我们可以用单调队列维护. 但是二维平面上单调队列怎么用? 我们先对行处理 ...

  5. 【DP】【单调队列】洛谷 P2216 [HAOI2007]理想的正方形 题解

        算是单调队列的复习吧,不是很难 题目描述 有一个$a\times b$的整数组成的矩阵,现请你从中找出一个$n\times n$的正方形区域,使得该区域所有数中的最大值和最小值的差最小. 输入 ...

  6. [洛谷P2216][HAOI2007]理想的正方形

    题目大意:有一个$a\times b$的矩阵,求一个$n\times n$的矩阵,使该区域中的极差最小. 题解:二维$ST$表,每一个点试一下是不是左上角就行了 卡点:1.用了一份考试时候写的二维$S ...

  7. 洛谷 P2216 [HAOI2007]理想正方形

    洛谷 巨说这是一道单调队列好题,但是我并不是用单调队列做的诶. 如果往最暴力的方向去想,肯定是\(n^3\)的\(dp\)了. \(f[i][j][k]\)代表当前正方形的左上角定点是\((i,j)\ ...

  8. BZOJ1047或洛谷2216 [HAOI2007]理想的正方形

    BZOJ原题链接 洛谷原题链接 显然可以用数据结构或\(ST\)表或单调队列来维护最值. 这里采用单调队列来维护. 先用单调队列维护每一行的最大值和最小值,区间长为正方形长度. 再用单调队列维护之前维 ...

  9. 洛谷 2216 [HAOI2007]理想的正方形

    题目戳这里 一句话题意 给你一个a×b的矩形,求一个n×n的子矩阵,矩阵里面的最大值和最小值之差最小. Solution 这个题目许多大佬都是单调队列,但是我不是很会,只好用了比较傻逼的方法: 首先我 ...

  10. P2216 [HAOI2007]理想的正方形 (单调队列)

    题目链接:P2216 [HAOI2007]理想的正方形 题目描述 有一个 \(a\times b\)的整数组成的矩阵,现请你从中找出一个 \(n\times n\)的正方形区域,使得该区域所有数中的最 ...

随机推荐

  1. 昨天太晚了,今天教你用Debug模式来分析程序执行顺序

    还是以昨天的XML文件解析来做栗子,希望通过这个好吃的栗子可以举一反三 学会用debug来看源码和找Bug 事件类型主要有五种START_DOCUMENT:xml头的事件类型    = 0END_DO ...

  2. JetBrains PyCharm(Community版本)的下载、安装和初步使用

    不多说,直接上干货! 首先谈及这款软件,博主我用的理由:搞机器学习和深度学习! 想学习Python的同学们,在这里隆重介绍一款 Python 的开发工具 pyCharm IDE.这是我最喜欢的 Pyt ...

  3. OpenGL进阶之Instancing

    Instancing Instancing绘制我想很多童鞋都不陌生,这个技术主要用来快速渲染大量相同的几何体,可以大大提高绘制效率.每个instance在shader中都有一个独一无二的索引,可以用来 ...

  4. java NIO之SelectedKey

    SelectedKey是channel与Selector绑定的标记,每将一个channel注册到一个selector就会产生一个SelectedKey,并将这个SelectedKey放入到Select ...

  5. HDU 1698——Just a Hook——————【线段树区间替换、区间求和】

    Just a Hook Time Limit:2000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Submit  ...

  6. mysql中时间日期函数

    转自:mysql 中 时间和日期函数 一.MySQL 获得当前日期时间 函数 1.1 获得当前日期+时间(date + time)函数:now() mysql> select now(); +- ...

  7. C/C++中的auto关键词

    C语言 auto被解释为一个自动存储变量的关键字,也就是申明一块临时的变量内存. 例如: auto double a=3.7; 表示a为一个自动存储的临时变量. C++语言 C++ 98标准/C++0 ...

  8. Prime Numbers in a Grid素数网格

    &/@ Shorthand notation for Map If[PrimeQ[#], Framed@Style[#, Orange, Bold, 15], #] & /@ Rang ...

  9. 【Linux】Windows与Linux之间的文件共享(基于网络)

    切记:Linux的安全机制的存在--iptables和selinux. 一.操作前提 1.1 从Windows能够ping通Linux 1.2 关闭Linux防火墙 command1:/etc/ini ...

  10. Not able to find Java executable or version转载

    转载地址:https://blog.csdn.net/qq_40902122/article/details/79437991 findstr' 不是内部或外部命令,也不是可运行的程序或批处理文件.N ...