P2216 理想的正方形

(为什么要写这篇题解?因为我β搞的心态炸了)

食用此题解所需:有基础的双端队列知识与一只可爱的 \(C++\)

传送门:起飞!

1. 思考

嗯,一看数据范围,\(a,b \leq 1,000\) ,就知道这道题一定是一道 \(\operatorname{O}(ab)\) 的题(因为输入就已经达到 \(100,000\) 级别了,就算是 \(\operatorname{O}(abn)\) 也过不去,顶多加一两个常数)

所以,\(\operatorname{O}(abn^2)\) 的暴力是过不去哒!

既然暴力过不去,那么 \(\dots\) 就换一个角度!

先单独考虑一个 \(n \cdot n\) 的正方形,我们可以把它切片,切成每一份为 \(1 \cdot n\) 的长方形,得出每一片长方形的最小值、最大值,然后再合并,也就是取最小、最大。

(图不严谨,只是稍微解释一下冲向的描述)

然后考虑横向的一排正方形,观察每个正方形最上面的一块切片,发现 \(\dots\) 没错,这就是一个 区间移动求最值 的过程,而区间的长度恰恰为 \(n\) 。

我们可以将最大值与最小值存下来,那么 \(dpmin_{i,j}\) 就表示第 \(i\) 行 \(j-n+1\) ~ \(j\) 这一条切片的最小值(最大值同理),显然,这玩意儿可以用双端队列优化。

接下来,考虑纵向转移:将一个正方形最右边的一列割出来,由于这一列每一个坐标对应的 \(dpmin\) 值都相当与一条长度为 \(n\) 的切片,所以这一列上的 \(n\) 个 \(dpmin\) 值的最小值就是这个正方形的最小值。观察正方形纵向移动,这一列的变化 \(\dots\) 也是 区间移动求最值 !(当然啦,最大值也是同理)

那么,在纵向求值后,每一个正方形的最大最小值就都求出来了。这道题,也就过了。

这样,我们只需一个 \(dpmin\) 数组,一个 \(dpmax\) 数组,一个存储输入数据的数组(可以优化成一维),和两个双端队列(重复使用,一个记最大值,一个记最小值),时间复杂度接近 \(\operatorname{O}(ab)\) (双端队列操作也要时间,但是比较快的)

2. 警钟敲烂!

  1. STL 使用前先判非空

  2. 两个双端队列代码差不多,但是千万别直接 Ctrl+C,Ctrl+V 然后改!容易混淆或漏掉!建议重新手写!

3. 代码

直接抄的话是会错的啦!是会 \(AF\) 的啦!

#include<bits/stdc++.h>
using namespace std;
int a,b,n,vis[1005],dp1[1005][1005],dp2[1005][1005];
deque<int> quemin,quemax;
int main() {
scanf("%d%d%d",&a,&b,&n);
for(int i=1;i<=a;i++) {
// 清空双端队列
while(!quemin.empty()) quemin.pop_back();// 相比 pop_front 更快一些
while(!quemax.empty()) quemax.pop_back();
// 横向区间最值问题
for(int j=1;j<=b;j++) {
scanf("%d",&vis[j]);
// 插入最小值队列
while(!quemin.empty()&&quemin.front()<=j-n) quemin.pop_front();
while(!quemin.empty()&&vis[quemin.back()]>=vis[j]) quemin.pop_back();
quemin.push_back(j),dp1[i][j]=vis[quemin.front()];
// 插入最大值队列
while(!quemax.empty()&&quemax.front()<=j-n) quemax.pop_front();
while(!quemax.empty()&&vis[quemax.back()]<=vis[j]) quemax.pop_back();
quemax.push_back(j),dp2[i][j]=vis[quemax.front()];
}
}
// 纵向更新双端队列,求出答案
int ans=1e9;
for(int j=1;j<=b;j++) {// 纵向
// 基本同上
while(!quemin.empty()) quemin.pop_back();
while(!quemax.empty()) quemax.pop_back();
for(int i=1;i<=a;i++) {
while(!quemin.empty()&&quemin.front()<=i-n) quemin.pop_front();
while(!quemin.empty()&&dp1[quemin.back()][j]>=dp1[i][j]) quemin.pop_back();
quemin.push_back(i);
while(!quemax.empty()&&quemax.front()<=i-n) quemax.pop_front();
while(!quemax.empty()&&dp2[quemax.back()][j]<=dp2[i][j]) quemax.pop_back();
quemax.push_back(i);
if(i>=n&&j>=n) ans=min(ans,dp2[quemax.front()][j]-dp1[quemin.front()][j]);
}
}
printf("%d\n",ans);
return 1;// 抄代码有风险,做题请自己做,谢谢
}

P2216 理想的正方形 题解的更多相关文章

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

    洛谷P2216 理想的正方形 题目链接 思路: 直接暴力显然不可行,可以发现每一个矩形向右边扩展时是一列一列增加,于是可以想到单调队列,用数组来维护当前每列的最大值.因为行也有限制,所以还要用一个单调 ...

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

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

  3. 洛谷P2216 理想的正方形

    题目描述 有一个a*b的整数组成的矩阵,现请你从中找出一个n*n的正方形区域,使得该区域所有数中的最大值和最小值的差最小. 输入输出格式 输入格式: 第一行为3个整数,分别表示a,b,n的值 第二行至 ...

  4. BZOJ1047:[HAOI2007]理想的正方形——题解

    http://www.lydsy.com/JudgeOnline/problem.php?id=1047 https://www.luogu.org/problemnew/show/P2216#sub ...

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

    二维单调队列 先横向跑一边单调队列,记录下每一行长度为n的区间的最值 在纵向跑一边单调队列,得出结果 注意,mi要初始化为一个足够大的数 #include <iostream> #incl ...

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

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

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

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

  8. P2216 [HAOI2007]理想的正方形 方法记录

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

  9. 【洛谷P2216】[HAOI2007]理想的正方形

    理想的正方形 [题目描述] 一个a*b的矩阵,从中取一个n*n的子矩阵,使所选矩阵中的最大数与最小数的差最小. 思路: 二维的滑动窗口 对于每行:用一个单调队列维护,算出每个长度为n的区间的最大值和最 ...

  10. AC日记——[HAOI2007]理想的正方形 P2216

    [HAOI2007] 理想的正方形 思路: 正解多个单调队列: 但是我用树套树水了过去: 来,上代码: #include <cstdio> #include <cstring> ...

随机推荐

  1. 可持久化 01-trie 简记

    本文略过了 trie 和 可持久化的介绍,如果没学过请先自学. 在求给定一个值 \(k\) 与区间中某些值的异或最大值时,可以考虑使用在线的数据结构可持久化 01-trie 来维护. 01-trie ...

  2. FunProxy - 使用 Rust 构建跨平台全链路测试抓包代理工具

    作者:vivo 互联网大前端团队- Song Jiachao 在软件开发过程中,软件测试对于保障软件质量和用户满意度起着关键作用.为最大程度上提升软件品质,我们积极开展全链路测试实践,打造了用Rust ...

  3. Dify 架构全景:从模块设计到部署实践的完整指南

    项目概述 Dify 是一个开源的 LLM 应用开发平台,提供直观的界面,结合了AI Agent工作流.RAG 管道.智能体能力.模型管理和可观察性功能等,使用户能够快速从原型转向生产环境.Dify 允 ...

  4. Error: A JNI error has occurred, please check your installation and try again Exception in thread "main" java.lang.UnsupportedClassVersionError: HelloWorld has been compiled by a more

    一个新手容易遇到的问题,电脑上装了多个版本的java,比如8和11,导致javac和java的版本不一样 在控制面板里将其他版本卸载,留个8就行 然后在环境变量里重新配置一下就ok

  5. maven安装教程(亲测有用)

    先去https://maven.apache.org/download.cgi下第二个: 自己下不下来的,微信搜我公众号[勾玉技术]发送关键字[maven]获取百度云链接下载. 解压到任意文件夹,记得 ...

  6. MQTT协议与ODOO的结合使用

     一.MQTT简述      MQTT(Message Queuing Telemetry Transport,消息队列遥测传输协议),是一种基于发布/订阅(publish/subscribe)模式的 ...

  7. MySQL 生成随机字符串 uuid

      MySQL 使用函数 uuid()可以生成随机字符串,方法如下: select replace(uuid(),"-","") as uuid;   最后,楼 ...

  8. 关于cc3复现以及绕过思路

    关于cc3复现以及绕过思路 (文章简略许多,可以的话,可以看看之前之前发布的文章) 绕过思路:动态加载字节码绕过Runtime,exec被过滤 在前面两个篇章中我们学习了cc1,cc6和动态加载字节码 ...

  9. 插件分享 | 善用 VSCode 内置的效率神器 Emmet 插件提升前端开发效率

    在 VSCode 出现之前,Emmet 插件就在前端领域玩得风生水起,当时的 Sublime Text 装上此插件,前端的编码效率那感觉就如同 2G 网络到 5G 网络的差别一般. 后来 VSCode ...

  10. 用AI工具ChatMoney一键创作,让你的公众号文章流量飙升!

    本文由 ChatMoney团队出品 引言 想不想你的公众号文章一炮而红?是不是羡慕那些动不动就10W+的爆款文章?别眼红了,用ChatMoney,你也可以做到!这货可不是普通的写作工具,它是你的文章变 ...