当前位置: 首页 > news >正文

【题解】P2216 [HAOI2007] 理想的正方形 [单调队列]

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

生病了,做道简单题。


注意到数据范围,a*b*n*n 肯定不行,转而思考 a*b 或 a*n

我们可以预处理出每一行 n 长度范围的最大最小值,线性范围求极值,容易想到单调队列。

枚举每一行,固定 i 再枚举 n 长度范围开始的 j,用单调队列求出最大值和最小值。

这里可以找一个函数求,因为最大值和最小值的代码差不了多少。

求出第 i 行从第 j 个开始的 n 范围最大值和最小值,

还要求出从(i, j)开始的 n * n 的方阵的最大值和最小值。

可以枚举每一列,固定 j 再枚举 n 长度范围开始的 i。

为什么要反着来呢?因为之前每一行的 j 我们已经处理过了。

现在要单调队列的是 n 行的同一个 j,所以要先枚举 j。

这里也可以造一个函数。

这样就可以省下 n*n 的时间复杂度,为 O(a*b)

考虑定义数组:

const int N = 1e3 + 10;int mat[N][N];   // 题目给出的 a * b 矩阵
int mx[N][N];   // [i][j]:表示第 i 行从第 j 个开始的 n 范围最大值
int mn[N][N];   // [i][j]:表示第 i 行从第 j 个开始的 n 范围最小值
int mx_[N][N];   // [i][j]:从(i, j)开始的 n * n 的方阵的最大值
int mn_[N][N];   // [i][j]:从(i, j)开始的 n * n 的方阵的最小值
int q[N];       // 单调队列数组

得出 mx_ 和 mn_ 数组后,枚举开始方阵的列,枚举开始方阵的行,最大最小一减就是答案。

还有些实现的细节写代码里了:

#include <bits/stdc++.h>
using namespace std;const int N = 1e3 + 10;int mat[N][N];   // 题目给出的 a * b 矩阵
int mx[N][N];   // [i][j]:表示第 i 行从第 j 个开始的 n 范围最大值
int mn[N][N];   // [i][j]:表示第 i 行从第 j 个开始的 n 范围最小值
int mx_[N][N];   // [i][j]:从(i, j)开始的 n * n 的方阵的最大值
int mn_[N][N];   // [i][j]:从(i, j)开始的 n * n 的方阵的最小值
int q[N];       // 单调队列数组
int a, b, n;// 处理一行:t[1...b],结果存入 m[1...b - n + 1]
void get_m(int m[], int t[], int flag) {   // 数组传入函数就是指针,也就是 & 引用 int l = 1, r = 0;for (int j = 1; j <= b; j++) {// 维护单调队列while (l <= r && ((t[q[r]] <= t[j] && flag) || (t[q[r]] >= t[j] && !flag))) {r--;}q[++r] = j;// 移除过期元素while (l <= r && q[l] + n - 1 < j) {l++;}// 从第 n 个位置开始记录结果if (j >= n) {m[j - n + 1] = t[q[l]];}}
}// 处理一列 j:从 mx[i][j] 或 mn[i][j] 中取 i=1..a,结果存入 m[i][j] for i=1..a-n+1
void get_m_(int m[][N], int t[][N], int flag, int j) {   // 二维数组传入必须指定第二维大小int l = 1, r = 0;for (int i = 1; i <= a; i++) {while (l <= r && ((t[q[r]][j] <= t[i][j] && flag) || (t[q[r]][j] >= t[i][j] && !flag))) {r--;}q[++r] = i;while (l <= r && q[l] + n - 1 < i) {l++;}if (i >= n) {m[i - n + 1][j] = t[q[l]][j];}}
}int main() {ios::sync_with_stdio(false);cin.tie(0);cin >> a >> b >> n;for (int i = 1; i <= a; i++) {for (int j = 1; j <= b; j++) {cin >> mat[i][j];}}// 对每一行,计算滑动窗口最大值和最小值(窗口大小 n)for (int i = 1; i <= a; i++) {get_m(mx[i], mat[i], 1);   // 最大值get_m(mn[i], mat[i], 0);   // 最小值}// 对每一列 j(注意:mx[i] 只有 [1..b-n+1] 有效)for (int j = 1; j <= b - n + 1; j++) {get_m_(mx_, mx, 1, j);   // 列方向最大值get_m_(mn_, mn, 0, j);   // 列方向最小值}int ans = 1e9;for (int i = 1; i <= a - n + 1; i++) {for (int j = 1; j <= b - n + 1; j++) {ans = min(ans, mx_[i][j] - mn_[i][j]);}}cout << ans << "\n";return 0;
}

http://www.dtcms.com/a/516223.html

相关文章:

  • UE基础操作2
  • Java IDEA学习之路:第五、六周课程笔记归纳
  • 亚马逊云代理商:怎么使用AWS WAF?
  • 茂名建设企业网站建网站为什么要租空间
  • SOAP 实例详解
  • 【C++】多态深度解析:虚函数表与动态绑定的奥秘
  • 腾讯云网站建设教程企业名录app
  • 重庆做网站有哪些医疗网站建设
  • 语音识别技术之科大讯飞在线API
  • 从案例到实践:仓颉编程语言入门核心知识点全解析
  • VR环境中的概念
  • 闽侯县住房和城乡建设局官方网站猪八戒官网做网站专业吗
  • 十个app制作网站wordpress目录插件
  • PHP全电发票OFD生成实战
  • 利用DuckDB SQL求解集合数学题
  • 做新闻h5网站专业网站建设费用报价
  • 个人网站开发的环境海南省建设网站的公司电话号码
  • C++学习:C++11关于类型的处理
  • LayoutManager
  • 网站建设公司盈利分析网站建设需要哪些的ps
  • QML学习笔记(四十六)QML与C++交互:Q_PROPERTY宏映射
  • 培训学校 网站费用购物商城网站建设方案
  • 黑马商城day5-服务保护和分布式事务
  • 【实证分析】地市人才及资本创新要素流动数据集-含代码(2003-2023年)
  • 【学习系列】SAP RAP 16:RAP应用部署集成至Fiori Launchpad 【On-Premise】
  • 01-JavaScript基础
  • 万亿国债助力应急行业-多链路聚合通信路由在应急项目中的解决方案和技术需求
  • CSS3 超实用属性:pointer-events (可穿透图层的鼠标事件)
  • 企业做网站公司有哪些wordpress 积分支付
  • Java线程阻塞状态