【算法题解】Bindian 山丘信号问题(E. Bindian Signaling)

news/2024/12/27 9:16:16/

问题描述

在 Berland 古老的 Bindian 部落中,首都被 nn 座山丘围成一个圆环,每个山丘上都有一名守望者,日夜观察着周围的情况。

如果有危险,守望者可以在山丘上点燃篝火。两座山丘的守望者可以看到彼此的信号,条件是:

  1. 沿着两座山丘之间的圆弧(顺时针或逆时针方向)没有比这两座山丘更高的山丘。

需要计算有多少对山丘可以互相看见信号。


输入格式

  • 第一行包含一个整数 nn,表示山丘的数量 3≤n≤1063 \leq n \leq 10^6。
  • 第二行包含 nn 个整数,表示按顺时针顺序排列的山丘高度。所有高度均为正整数,范围为 11 至 10910^9。

输出格式

输出能互相看见信号的山丘对数。


示例输入输出

示例 1

输入:
5
1 2 4 5 3输出:
7

示例 2

输入:
4
3 3 3 3输出:
12

解题思路

这是一个经典的「单调栈」问题,涉及到可见性和环形结构处理,分为以下几步:

1. 问题简化

  • 如果所有山丘的高度都相同,则每一对山丘都可以互相看见,答案是 n×(n−1)n \times (n - 1)。
  • 对于一般情况,使用单调栈来解决。

2. 单调栈的作用

通过单调栈,我们可以快速找到:

  • 当前山丘是否有更高的山丘阻挡。
  • 当前山丘可以看到多少个较低或等高的山丘。

3. 环形结构的处理

由于山丘排列是圆环结构,我们需要遍历两次数组(顺时针和逆时针)来模拟圆环的可见性。

4. 复杂度要求

由于 nn 的范围高达 10610^6,我们需要:

  • 时间复杂度:O(n)O(n)。
  • 空间复杂度:O(n)O(n)。

代码实现

以下是 Python 的完整代码实现:

def count_visible_pairs(n, heights):# 如果所有山丘高度相同,则直接计算所有山丘对if len(set(heights)) == 1:return n * (n - 1)# 单调栈方法,计算可见的山丘对def calculate_pairs(heights):stack = []total_pairs = 0# 遍历每个山丘for h in heights:count = 1# 单调栈:移除较小或相等的山丘while stack and stack[-1][0] <= h:top = stack.pop()total_pairs += top[1]if top[0] == h:count += top[1]# 栈顶还有元素,说明能看到当前山丘if stack:total_pairs += 1# 将当前山丘加入栈stack.append((h, count))return total_pairs# 计算顺时针方向的可见山丘对linear_pairs = calculate_pairs(heights)# 计算逆时针方向的可见山丘对reverse_pairs = calculate_pairs(heights[::-1])# 总对数为顺时针和逆时针对数之和,但需要减去重复计算的部分total_pairs = linear_pairs + reverse_pairs - nreturn total_pairs# 输入处理
n = int(input())
heights = list(map(int, input().split()))# 计算并输出结果
print(count_visible_pairs(n, heights))

样例解析

示例 1

输入

5
1 2 4 5 3

输出

7

解析

  • 山丘对可以互相看见的情况为:
    (1, 2), (2, 3), (3, 4), (3, 5), (4, 3), (5, 3), (2, 1)。

示例 2

输入

4
3 3 3 3

输出

12

解析

  • 所有山丘高度相同,所有对均可互相看见。
    总共有 4×(4−1)=124 \times (4 - 1) = 12 对。

复杂度分析

  1. 时间复杂度

    • 单调栈遍历一次数组的时间复杂度为 O(n)O(n)。
    • 因为需要两次遍历,整体时间复杂度为 O(2n)=O(n)O(2n) = O(n)。
  2. 空间复杂度

    • 单调栈的最大深度为 nn,空间复杂度为 O(n)O(n)。

算法可以高效解决 n=106n = 10^6 的大规模输入问题。


总结

  • 本题的核心是「单调栈」和「环形数组」的结合。
  • 通过单调栈高效计算每个山丘的可见性,避免了暴力计算的 O(n2)O(n^2) 时间复杂度。
  • 在环形数组中,我们通过两次遍历实现了对所有方向的处理。

这道题展示了如何用数据结构优化传统的暴力算法,是经典的竞赛题之一。


如果觉得文章有帮助,欢迎点赞、收藏和关注!有其他思路或疑问,也欢迎在评论区讨论 😊!


http://www.ppmy.cn/news/1558489.html

相关文章

算法的学习笔记— 圆圈中最后剩下的数(牛客JZ62)

&#x1f3e0;个人主页&#xff1a;尘觉主页 文章目录 62. 圆圈中最后剩下的数题目链接题目描述解题思路Java 实现思考分析&#x1f604;总结 62. 圆圈中最后剩下的数 题目链接 NowCoder 题目描述 让小朋友们围成一个大圈。然后&#xff0c;随机指定一个数 m&#xff0c;让…

Mysql5.7配置主从实际操作记录

&#x1f440; 什么是MySQL主从配置 指一台服务器充当主数据库服务器&#xff0c;另一台或多台服务器充当从数据库服务器&#xff0c;主服务器中的数据自动复制到从服务器之中。 对于多级复制&#xff0c;数据库服务器即可充当主机&#xff0c;也可充当从机。MySQL主从复制的…

【面试系列】深入浅出 Spring

熟悉Spring&#xff0c;对IOC、AOP、Bean生命周期、循环依赖等有深入了解。 面试题整理 描述 Spring Context 初始化的流程介绍 Bean 的生命周期及作用域Bean 的构造方法、 PostConstruct注解、InitializingBean、init-method 的执行顺序&#xff1f;Spring 如何解决循环依赖&…

C语言从入门到放弃教程

C语言从入门到放弃 1. 介绍1.1 特点1.2 历史与发展1.3 应用领域 2. 安装2.1 编译器安装2.2 编辑器安装 3. 第一个程序1. 包含头文件2. 主函数定义3. 打印语句4. 返回值 4. 基础语法4.1 注释4.1.1 单行注释4.1.2 多行注释 4.2 关键字4.2.1 C语言标准4.2.2 C89/C90关键字&#xf…

【机器学习案列】车牌自动识别系统:基于YOLO11的高效实现

&#x1f9d1; 博主简介&#xff1a;曾任某智慧城市类企业算法总监&#xff0c;目前在美国市场的物流公司从事高级算法工程师一职&#xff0c;深耕人工智能领域&#xff0c;精通python数据挖掘、可视化、机器学习等&#xff0c;发表过AI相关的专利并多次在AI类比赛中获奖。CSDN…

Metricbeat安装教程——Linux——Metricbeat监控ES集群

Metricbeat安装教程——Linux 一、安装 下载安装包&#xff1a; 官网下载地址&#xff1a;https://www.elastic.co/cn/downloads/beats/metricbeat 上传包到linux 切换到安装目录下 解压&#xff1a;tar -zxvf metricbeat-7.17.1-linux-x86_64.tar.gz 重命名安装文件夹 mv met…

【Compose multiplatform教程07】多平台常用组件和重要组件目录

一、基础交互与显示组件 Text 查看示例 功能说明&#xff1a;用于在界面上显示文本内容&#xff0c;支持设置字体、大小、颜色、样式&#xff08;如加粗、斜体、下划线&#xff09;等属性&#xff0c;满足不同的文本展示需求&#xff0c;可传达各种信息给用户。示例场景&#…

大模型日报 2024-12-20

大模型日报 2024-12-20 大模型资讯 标题&#xff1a; OpenAI发布季第十一天&#xff1a;ChatGPT深度集成Mac应用&#xff0c;从Chatbot变身AI Agent 摘要&#xff1a;本文报道了OpenAI在其发布季第十一天推出的ChatGPT与Mac应用的深度集成&#xff0c;标志着ChatGPT从单一的会话…