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

问题描述

在 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 - n

    return 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) 时间复杂度。
  • 在环形数组中,我们通过两次遍历实现了对所有方向的处理。

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


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

相关推荐
Wang's Blog5 小时前
Java 项目实战: 交友项目:登录链路回顾与今日任务地图
java·开发语言·状态模式·交友
信誓旦旦的程序猿5 小时前
【Python量化实战宝典 #08】可转债与债券接口手册:转股价·溢价率·纯债价值(Python 可跑)
java·python·股票数据api·股票数据api接口·股票api数据接口·股票量化数据api·股票量化数据接口
砚底藏山河5 小时前
python量化:行情数据回溯
java·开发语言·python·金融·maven
今年下半年5 小时前
AI智能体项目实战记录(02):初始化 Python 项目
开发语言·人工智能·python·fastapi
Williamtym6 小时前
PickGo Lab实践:用浏览器、Python和MCP串起机器人搬运仿真
开发语言·python·机器人
HPtiger6 小时前
数据结构——选择排序
数据结构·算法·排序算法
康实训6 小时前
老年评估仿真实训平台架构设计与老年人能力评估实训室教学落地实践
大数据·人工智能·算法·实训室·实训室建设
DongQiShanRen6 小时前
六根硬件映射(四):归属澄清、两处不一致与卷十一总表
开发语言·人工智能·算法·rust·哈希算法·集成学习
CS创新实验室6 小时前
Python 对象“死“了之后去了哪?——引用计数与分代垃圾回收
开发语言·jvm·python
CCblandy6 小时前
雪花 ID 四个边界实测:时钟回拨重号 500 个,前端 JSON.parse 直接丢精度
后端·python·算法·性能优化·架构