【洛谷P2216】[HAOI2007]理想的正方形
理想的正方形
【题目描述】
一个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]理想的正方形的更多相关文章
- 洛谷 P2216 [HAOI2007]理想的正方形
P2216 [HAOI2007]理想的正方形 题目描述 有一个a*b的整数组成的矩阵,现请你从中找出一个n*n的正方形区域,使得该区域所有数中的最大值和最小值的差最小. 输入输出格式 输入格式: 第一 ...
- 洛谷P2216: [HAOI2007]理想的正方形 单调队列优化DP
洛谷P2216 )逼着自己写DP 题意: 给定一个带有数字的矩阵,找出一个大小为n*n的矩阵,这个矩阵中最大值减最小值最小. 思路: 先处理出每一行每个格子到前面n个格子中的最大值和最小值.然后对每一 ...
- 洛谷 P2216 [HAOI2007]理想的正方形 || 二维RMQ的单调队列
题目 这个题的算法核心就是求出以i,j为左上角,边长为n的矩阵中最小值和最大值.最小和最大值的求法类似. 单调队列做法: 以最小值为例: q1[i][j]表示第i行上,从j列开始的n列的最小值.$q1 ...
- 洛谷P2216 HAOI2007 理想的正方形 (单调队列)
题目就是要求在n*m的矩形中找出一个k*k的正方形(理想正方形),使得这个正方形内最值之差最小(就是要维护最大值和最小值),显然我们可以用单调队列维护. 但是二维平面上单调队列怎么用? 我们先对行处理 ...
- 【DP】【单调队列】洛谷 P2216 [HAOI2007]理想的正方形 题解
算是单调队列的复习吧,不是很难 题目描述 有一个$a\times b$的整数组成的矩阵,现请你从中找出一个$n\times n$的正方形区域,使得该区域所有数中的最大值和最小值的差最小. 输入 ...
- [洛谷P2216][HAOI2007]理想的正方形
题目大意:有一个$a\times b$的矩阵,求一个$n\times n$的矩阵,使该区域中的极差最小. 题解:二维$ST$表,每一个点试一下是不是左上角就行了 卡点:1.用了一份考试时候写的二维$S ...
- 洛谷 P2216 [HAOI2007]理想正方形
洛谷 巨说这是一道单调队列好题,但是我并不是用单调队列做的诶. 如果往最暴力的方向去想,肯定是\(n^3\)的\(dp\)了. \(f[i][j][k]\)代表当前正方形的左上角定点是\((i,j)\ ...
- BZOJ1047或洛谷2216 [HAOI2007]理想的正方形
BZOJ原题链接 洛谷原题链接 显然可以用数据结构或\(ST\)表或单调队列来维护最值. 这里采用单调队列来维护. 先用单调队列维护每一行的最大值和最小值,区间长为正方形长度. 再用单调队列维护之前维 ...
- 洛谷 2216 [HAOI2007]理想的正方形
题目戳这里 一句话题意 给你一个a×b的矩形,求一个n×n的子矩阵,矩阵里面的最大值和最小值之差最小. Solution 这个题目许多大佬都是单调队列,但是我不是很会,只好用了比较傻逼的方法: 首先我 ...
- P2216 [HAOI2007]理想的正方形 (单调队列)
题目链接:P2216 [HAOI2007]理想的正方形 题目描述 有一个 \(a\times b\)的整数组成的矩阵,现请你从中找出一个 \(n\times n\)的正方形区域,使得该区域所有数中的最 ...
随机推荐
- js模拟实现哈希表
在算法中,尤其是有关数组的算法中,哈希表的使用可以很好的解决问题,所以这篇文章会记录一些有关js实现哈希表并给出解决实际问题的例子. 说明: 这篇博客所写并不是真正意义的哈希表,只是与哈希表的使用有相 ...
- 05-ognl基本语法
1 基本取值 @Test //1基础语法演示-基本取值 //取出root中的属性值 public void fun2() throws Exception{ //1 准备OGNLcontext Ogn ...
- 02-struts2结果常见的四种处理方式
1 转发 <!--转发 --> <action name="Demo1Action" class="www.test.a_result.Demo1Act ...
- 这真的该用try-catch吗?
前言 我有个技能,就是把“我”说的听起来特别像“老子”. 以前是小喽啰的时候,会跟领导说“我!不加班.”,听起来就像“老子不加班!”一样.到最后发现,我确实没有把计划内的工作拖到需要加班才能完成,这个 ...
- git读书笔记以及使用技巧
[添加文件] git add 把文件修改添加到暂存区 git commit -m '' 把暂存区的所有内容提交到当前分支 [查看历史] git log 查看提交历史 git log -- ...
- Ubuntu以及CentOS7修改ssh端口号详细步骤
1.Ubuntu修改ssh端口号步骤: 1.修改sshd.config文件.执行vim etc/ssh/sshd_config.增加上我们需要增加的ssh的端口号.图例增加了5309的端口号. ESC ...
- keepalive学习之软件设计
软件架构如下图所示: Keepalived 完全使用标准的ANSI/ISO C写出. 该软件主要围绕一个中央I/O复用分发器而设计,这个I/O复用分发器提供网络实时功能. 主要设计目标着重于从所有的模 ...
- 使用Git(msysgit)和TortoiseGit上传代码到GitHub
1.准备 下载Git for Windows (msysgit) 下载TortoiseGit 安装过程很简单,一直点击下一步到完成即可. 2.配置TortoiseGit 1.双击TortoiseGit ...
- jquery监控input输入框的变化
(function($) { $.fn.watch = function(callback) { return this.each(function() { //缓存以前的值 $.data(this, ...
- 05.if结构
分支结构:if if-else 选择结构:if else-if switch-case 循环结构:while do-while for foreach if语句 语法: if(判断条件) { //要 ...