【第十六届 蓝桥杯 省 C/Python A/Java C 登山】题解

题目链接:P12169 [蓝桥杯 2025 省 C/Python A/Java C] 登山

思路来源

一开始想的其实是记搜,但是发现还有先找更小的再找更大的这种路径,所以这样可能错过某些最优决策,这样不行。

于是我又想能不能从最大值出发往回搜,手玩了一下发现其实和记搜没什么区别,无非是把边给反向了。

那可能的做法就是强连通分量?我当时板子都掏出来了,但是模拟了一番之后就发现可以用并查集。

下面是正文。

算法:并查集

由于行列是同一套逻辑,所以下面只说同一列内的行操作,同一行内的列操作直接照抄即可。

设现在我们在 ( x , y ) (x, y) (x,y),且存在点 ( i , y ) (i, y) (i,y) 满足 i > x i > x i>x a i , y < a x , y a_{i, y} < a_{x, y} ai,y<ax,y,那么我们可以从 ( x , y ) (x, y) (x,y) ( i , y ) (i, y) (i,y) 连边表示 ( x , y ) (x, y) (x,y) 可达 ( i , y ) (i, y) (i,y)

那么同理,如果我们在 ( i , y ) (i, y) (i,y),根据题中所说, ( x , y ) (x, y) (x,y) 满足 x < i x < i x<i a x , y > a i , y a_{x, y} > a_{i, y} ax,y>ai,y,同样可以从 ( i , y ) (i, y) (i,y) ( x , y ) (x, y) (x,y) 连边。

也就是说,只要存在一个逆序对,就有一对 双向边

但是直接 O ( n 2 ) O(n^2) O(n2) 遍历 O ( m ) O(m) O(m) 次来连边有点太狂野了,这复杂度也过不去,所以我们开始寻找逆序对连边的等价命题。

先给出命题:

对于第 j j j 列,设 p r e [ i ] pre[i] pre[i] 表示前 i i i 个元素的最大值, s u f [ i ] suf[i] suf[i] 表示 [ i , n ] [i, n] [i,n] 内元素的最小值,如果 p r e [ i ] > s u f [ i + 1 ] pre[i] > suf[i + 1] pre[i]>suf[i+1],就连一条 ( i , j ) (i, j) (i,j) ( i + 1 , j ) (i + 1, j) (i+1,j) 的边。

为了方便,做几点说明。

  • 逆序对连边生成的边集为 E 0 E_0 E0,相邻连边生成的边集为 E 1 E_1 E1
  • 简写 ( l , j ) (l, j) (l,j) ( r , j ) (r, j) (r,j) 连双向边为 l ⟺ r l \Longleftrightarrow r lr

下面证明二者等价。

若有 a l , j > a r , j a_{l, j} > a_{r, j} al,j>ar,j,那么有 l ⟺ r l \Longleftrightarrow r lr,那么对于 i ∈ [ l , r ) i \in [l, r) i[l,r),一定有 p r e [ i ] > s u f [ i + 1 ] pre[i] > suf[i + 1] pre[i]>suf[i+1],那也就是说, E 1 E_1 E1 会包含 l ⟺ l + 1 , l + 1 ⟺ l + 2 , ⋯ , r − 1 ⟺ r l \Longleftrightarrow l + 1, \ \ l + 1 \Longleftrightarrow l + 2, \ \ \cdots, \ \ r - 1 \Longleftrightarrow r ll+1,  l+1l+2,  ,  r1r,这相当于包含了一条 l ⟺ r l \Longleftrightarrow r lr 的双向边,所以 E 0 ⊆ E 1 E_0 \subseteq E_1 E0E1

若有 p r e [ i ] > s u f [ i + 1 ] pre[i] > suf[i + 1] pre[i]>suf[i+1],那么有 i ⟺ i + 1 i \Longleftrightarrow i + 1 ii+1,同时,由前缀最大和后缀最小的性质可以得到,必然存在 l ∈ [ 1 , i ] l \in [1, i] l[1,i] r ∈ ( i , n ] r \in (i, n] r(i,n],使得 a l , j > a r , j a_{l, j} > a_{r, j} al,j>ar,j,那么首先就有 l ⟺ r l \Longleftrightarrow r lr。如果 l < i l < i l<i,说明 a l , j > a i , j a_{l, j} > a_{i, j} al,j>ai,j,那么由题目条件有 l ⟺ i l \Longleftrightarrow i li,同理如果 i + 1 < r i + 1 < r i+1<r,那么 i + 1 ⟺ r i + 1 \Longleftrightarrow r i+1r,将这三条边合起来,就包含了一条 i ⟺ i + 1 i \Longleftrightarrow i + 1 ii+1 的双向边,所以 E 1 ⊆ E 0 E_1 \subseteq E_0 E1E0

综上, E 0 = E 1 E_0 = E_1 E0=E1,二者等价。

设我们这样得到了 N N N 个连通块,第 i i i 个连通块的大小为 s i z i siz_i sizi,其块内最大值为 max ⁡ i \max_i maxi,则最终答案为

∑ i = 1 N s i z i × m a x i . \sum\limits_{i = 1}^{N}siz_i \times max_i. i=1Nsizi×maxi.

时间复杂度 O ( n m ⋅ α ( n m ) ) O(\rm{nm \cdot \alpha(nm)}) O(nmα(nm))
  • 其中 α ( n m ) \rm{\alpha(nm)} α(nm) 是反阿克曼函数,一般可以看作 3 , 4 3, 4 3,4 左右的常数。
C++ Code
#include <bits/stdc++.h>using i64 = long long;struct DSU {std::vector<int> f, sz;DSU() {}DSU(int n) {init(n);}void init(int n) {f.resize(n);std::iota(f.begin(), f.end(), 0);sz.assign(n, 1);}int find(int x) {while (x != f[x]) {x = f[x] = f[f[x]];}return x;}int size(int x) {return sz[find(x)];}bool merge(int x, int y) {x = find(x);y = find(y);if (x == y) {return false;}sz[x] += sz[y];f[y] = x;return true;}bool same(int x, int y) {return find(x) == find(y);}
};template<class T>
void chmax(T &a, T b) {if (a < b) {a = b;}
}
constexpr int inf = std::numeric_limits<int>::max() / 2;int main() {std::ios::sync_with_stdio(false);std::cin.tie(nullptr);std::cout << std::fixed << std::setprecision(6);int n, m;std::cin >> n >> m;const int N = n * m;std::vector<int> a(N);for (int i = 0; i < n; i++) {for (int j = 0; j < m; j++) {std::cin >> a[i * m + j];}}DSU dsu(N);for (int i = 0; i < n; i++) {std::vector pre(m + 1, 0);std::vector suf(m + 1, inf);for (int j = 0; j < m; j++) {pre[j + 1] = std::max(pre[j], a[i * m + j]);}for (int j = m - 1; j >= 0; j--) {suf[j] = std::min(suf[j + 1], a[i * m + j]);}for (int j = 1; j < m; j++) {if (pre[j] > suf[j]) {dsu.merge(i * m + (j - 1), i * m + j);}}}for (int j = 0; j < m; j++) {std::vector pre(n + 1, 0);std::vector suf(n + 1, inf);for (int i = 0; i < n; i++) {pre[i + 1] = std::max(pre[i], a[i * m + j]);}for (int i = n - 1; i >= 0; i--) {suf[i] = std::min(suf[i + 1], a[i * m + j]);}for (int i = 1; i < n; i++) {if (pre[i] > suf[i]) {dsu.merge((i - 1) * m + j, i * m + j);}}}std::vector max(N, 0);for (int i = 0; i < N; i++) {chmax(max[dsu.find(i)], a[i]);}i64 ans = 0;for (int i = 0; i < N; i++) {if (dsu.find(i) == i) {ans += 1LL * dsu.size(i) * max[i];}}std::cout << 1.* ans / n / m << "\n";return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/77800.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

软件工程师中级考试-上午知识点总结(上)

我总结的这些都是每年的考点&#xff0c;必须要记下来的。 1. 计算机系统基础 1.1 码 符号位0表示正数&#xff0c;符号位1表示负数。补码&#xff1a;简化运算部件的设计&#xff0c;最适合进行数字加减运算。移码&#xff1a;与前几种不同&#xff0c;1表示&#xff0c;0表…

Python Cookbook-6.7 有命名子项的元组

任务 Python 元组可以很方便地被用来将信息分组&#xff0c;但是访问每个子项都需要使用数字索引&#xff0c;所以这种用法有点不便。你希望能够创建一种可以通过名字属性访问的元组。 解决方案 工厂函数是生成符合要求的元组的子类的最简单方法: #若在2.4中可使用operator…

win10设置软件开机自启

参考教程&#xff1a;windows10应用程序设置了开机启动&#xff0c;但没有自启_win10软件设置了自启动但是不能自启动-CSDN博客 主要设置是安全策略&#xff1a;

自注意力机制、多头自注意力机制、填充掩码 Python实现

原理讲解 【Transformer系列&#xff08;2&#xff09;】注意力机制、自注意力机制、多头注意力机制、通道注意力机制、空间注意力机制超详细讲解 自注意力机制 import torch import torch.nn as nn# 自注意力机制 class SelfAttention(nn.Module):def __init__(self, input…

【大模型】Browser-Use AI驱动的浏览器自动化工具

Browser-Use AI驱动的浏览器自动化工具 1. 项目概述2. 核心架构3. 实战指南3.1 环境安装3.2 快速启动3.3 进阶功能 4. 常见问题与解决5. 项目优势与局限6. 扩展资源7. 总结 1. 项目概述 项目地址&#xff1a;browser-use Browser-Use 是一个开源工具&#xff0c;旨在通过 AI 代…

ubuntu20.04安装安装x11vnc服务基于gdm3或lightdm这两种主流的显示管理器。

前言&#xff1a;在服务端安装vnc服务&#xff0c;可以方便的远程操作服务器&#xff0c;而不用非要插上显示器才行。所以在服务器上安装vnc是很重要的。在ubuntu20中&#xff0c;默认的显示管理器已经变为gdm3&#xff0c;它可以带来与 GNOME 无缝衔接的体验&#xff0c;强调功…

用银河麒麟 LiveCD 快速查看原系统 IP 和打印机配置

原文链接&#xff1a;用银河麒麟 LiveCD 快速查看原系统 IP 和打印机配置 Hello&#xff0c;大家好啊&#xff01;今天给大家带来一篇在银河麒麟操作系统的 LiveCD 或系统试用镜像环境下&#xff0c;如何查看原系统中电脑的 IP 地址与网络打印机 IP 地址的实用教程。在系统损坏…

C++——STL——容器deque(简单介绍),适配器——stack,queue,priority_queue

目录 1.deque&#xff08;简单介绍&#xff09; 1.1 deque介绍&#xff1a; 1.2 deque迭代器底层 1.2.1 那么比如说用迭代器实现元素的遍历&#xff0c;是如何实现的呢&#xff1f; 1.2.2 头插 1.2.3 尾插 1.2.4 实现 ​编辑 1.2.5 总结 2.stack 2.1 函数介绍 2.2 模…

Java并发编程-线程池

Java并发编程-线程池 线程池运行原理线程池生命周期线程池的核心参数线程池的阻塞队列线程池的拒绝策略线程池的种类newFixedThreadPoolnewSingleThreadExecutornewCachedThreadPoolnewScheduledThreadPool 创建线程池jdk的Executors(不建议&#xff0c;会导致OOM)jdk的ThreadP…

【前沿】成像“跨界”测量——扫焦光场成像

01 背景 眼睛是人类认识世界的重要“窗口”&#xff0c;而相机作为眼睛的“延伸”&#xff0c;已经成为生产生活中最常见的工具之一&#xff0c;广泛应用于工业检测、医疗诊断与影音娱乐等领域。传统相机通常以“所见即所得”的方式记录场景&#xff0c;传感器捕捉到的二维图像…

TM1640学习手册及示例代码

数据手册 TM1640数据手册 数据手册解读 这里我们看管脚定义DIN和SCLK&#xff0c;一个数据线一个时钟线 SEG1~SEG8为段码&#xff0c;GRID1~GRID16为位码&#xff08;共阴极情况下&#xff09; 这里VDD给5V 数据指令 数据命令设置 地址命令设置 显示控制命令 共阴极硬件连接图…

uni-app 开发企业级小程序课程

课程大小&#xff1a;7.7G 课程下载&#xff1a;https://download.csdn.net/download/m0_66047725/90616393 更多资源下载&#xff1a;关注我 备注&#xff1a;缺少两个视频5-14 tabs组件进行基本的数据展示和搜索历史 处理searchData的删除操作 1-1导学.mp4 2-10小程序内…

判断点是否在多边形内

代码段解析: const intersect = ((yi > y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); 第一部分:(yi > y) !== (yj > y) 作用:检查点 (x,y) 的垂直位置是否跨越多边形的当前边。 yi > y 和 yj > y 分别检查边的两个端…

【redis】集群 如何搭建集群详解

文章目录 集群搭建1. 创建目录和配置2. 编写 docker-compose.yml完整配置文件 3. 启动容器4. 构建集群超时 集群搭建 基于 docker 在我们云服务器上搭建出一个 redis 集群出来 当前节点&#xff0c;主要是因为我们只有一个云服务器&#xff0c;搞分布式系统&#xff0c;就比较…

[langchain教程]langchain03——用langchain构建RAG应用

RAG RAG过程 离线过程&#xff1a; 加载文档将文档按一定条件切割成片段将切割的文本片段转为向量&#xff0c;存入检索引擎&#xff08;向量库&#xff09; 在线过程&#xff1a; 用户输入Query&#xff0c;将Query转为向量从向量库检索&#xff0c;获得相似度TopN信息将…

C语言复习笔记--字符函数和字符串函数(下)

在上篇我们了解了部分字符函数及字符串函数,下面我们来看剩下的字符串函数. strstr 的使用和模拟实现 老规矩,我们先了解一下strstr这个函数,下面看下这个函数的函数原型. char * strstr ( const char * str1, const char * str2); 如果没找到就返回NULL指针. 下面我们看下它的…

FreeRTOS中的优先级翻转问题及其解决方案:互斥信号量详解

FreeRTOS中的优先级翻转问题及其解决方案&#xff1a;互斥信号量详解 在实时操作系统中&#xff0c;任务调度是基于优先级的&#xff0c;高优先级任务应该优先于低优先级任务执行。但在实际应用中&#xff0c;有时会出现"优先级翻转"的现象&#xff0c;严重影响系统…

深度学习-全连接神经网络

四、参数初始化 神经网络的参数初始化是训练深度学习模型的关键步骤之一。初始化参数&#xff08;通常是权重和偏置&#xff09;会对模型的训练速度、收敛性以及最终的性能产生重要影响。下面是关于神经网络参数初始化的一些常见方法及其相关知识点。 官方文档参考&#xff1…

GIS开发笔记(9)结合osg及osgEarth实现三维球经纬网格绘制及显隐

一、实现效果 二、实现原理 按照5的间隔分别创建经纬线的节点,挂在到组合节点,组合节点挂接到根节点。可以根据需要设置间隔度数和线宽、线的颜色。 三、参考代码 //创建经纬线的节点 osg::Node *GlobeWidget::createGraticuleGeometry(float interval, const osg::Vec4 …

《Relay IR的基石:expr.h 中的表达式类型系统剖析》

TVM Relay源码深度解读 文章目录 TVM Relay源码深度解读一 、从Constant看Relay表达式的设计哲学1. 类定义概述2. ConstantNode 详解1. 核心成员2. 关键方法3. 类型系统注册 3. Constant 详解1. 核心功能 二. 核心内容概述(1) Relay表达式基类1. RelayExprNode 和 RelayExpr 的…