S10-蓝桥杯 17822 乐乐的积木塔
摘要:本文详细解析蓝桥杯17822题"乐乐的积木塔",重点剖析题目中"连续递减积木塔"等绕口表述的真实含义,分享个人从困惑到理解的解题历程,并提供简洁的Python题解。
1. 题目描述 📋
1.1 问题描述
在乐乐的玩具箱中,有一系列的积木,每个积木上都标记有一个高度值。乐乐想要找出每个积木能够成为最高的连续递减积木塔的一部分的最大高度。对于每个积木,求出包含该积木的最长递减积木序列的长度。
1.2 输入格式
第一行包含一个整数 。
第二行包含 个整数,表示每个积木的高度。
1.3 输出格式
输出 个整数,每个整数代表以第 个积木为一部分的最长递减积木序列的长度。
1.4 样例
样例输入:
5
3 2 1 1 4
样例输出:
3 3 3 1 1
1.5 评测数据规模
1.6 运行限制
| 语言 | 最大运行时间 | 最大运行内存 |
|---|---|---|
| C++ | 1s | 256M |
| C | 1s | 256M |
| Java | 2s | 256M |
| Python3 | 3s | 256M |
| PyPy3 | 3s | 256M |
| Go | 3s | 256M |
| JavaScript | 3s | 256M |
总通过次数: 6 | 总提交次数: 6 | 通过率: 100%
1.7 难度与标签
- 难度:中 LV.8
- 标签:数学
1.8 原题链接
2. 题目理解难点分析 🤔
个人感受:这道题最大的难点其实在于题目的理解。我第一次看到这道题时,完全不知道"连续递减积木塔"是什么概念,对题目根本无从下手,最后只能求助豆包才搞明白题意。但一旦理解了题意,其实这道题非常简单。
2.1 什么是"连续递减积木塔"?
核心概念拆解:
这个题目名称听起来很唬人,其实拆解开来就是三个关键词:
- 连续:在原数组中位置连续(相邻),不能跳着选
- 递减:后面的数必须比前面的数小(严格递减)
- 积木塔:就是一个序列的比喻说法
通俗理解:
想象你把积木一块一块叠起来,每块积木的高度必须比下面那块矮,而且这些积木在原数组中必须是挨着的。
数学定义:
对于数组 ,如果存在一段连续子数组 满足: 那么这就是一个"连续递减积木塔"。
举例说明:
对于数组
[5, 3, 4, 2, 1]:
连续子序列 是否递减 说明 [5, 3]✅ 5 > 3,是递减 [3, 4]❌ 3 < 4,不是递减 [4, 2, 1]✅ 4 > 2 > 1,是递减 [5, 3, 4]❌ 3 < 4,不是递减 [5]✅ 单个元素, trivially 递减
本题要求:
对于数组中的每个位置,找出包含该位置的最长连续递减子序列的长度。
连续递减子序列参考资料:
2.2 "最高的连续递减积木塔的一部分的最大高度"是什么意思?
拆解这个绕口的句子:
原题说:"找出每个积木能够成为最高的连续递减积木塔的一部分的最大高度"
这句话确实有点绕,让我们一步步拆解:
第一层理解:"连续递减积木塔"
就是我们 2.1 节讲的,一段连续且递减的序列。
第二层理解:"最高的...一部分"
"最高"指的是塔的高度(即序列的长度)要尽可能长。 "一部分"意思是这个积木可以在塔的任何位置(顶部、中间、底部都行)。
第三层理解:整句话的意思
对于每个积木,我们要找:包含这个积木的最长连续递减序列有多长。
举例说明:
数组:
[5, 4, 3, 2, 6, 5, 4]分析第 3 个积木(值为 3):
- 包含 3 的连续递减序列有:
[5, 4, 3]→ 长度 3[4, 3]→ 长度 2[3]→ 长度 1[5, 4, 3, 2]→ 长度 4 ✅ 最长!- 所以第 3 个积木的答案是 4
再看原题样例:
输入:
[3, 2, 1, 1, 4]
位置 值 包含它的最长递减序列 长度 1 3 [3, 2, 1]3 2 2 [3, 2, 1]3 3 1 [3, 2, 1]3 4 1 [1]1 5 4 [4]1 输出:
3 3 3 1 1✓
关键洞察:
这道题本质上是求:每个位置作为"中间点"时,能向左延伸多远 + 能向右延伸多远 - 1(减去重复计算的自己)。
2.3 "求出包含该积木的最长递减积木序列的长度"是什么意思?
这句话是题目要求的核心:
题目最后说:"求出包含该积木的最长递减积木序列的长度"
这句话其实比前面那句更直接,让我们拆解一下:
关键词解析:
关键词 含义 包含该积木 这个积木必须在序列里面(可以是开头、中间、结尾) 最长 在所有满足条件的序列中,找长度最大的那个 递减积木序列 连续递减的序列(就是我们前面讲的"塔") 长度 序列中有多少个元素
整句话的意思:
对于数组中的每一个位置,输出一个数字,这个数字表示:包含这个位置的最长连续递减序列有多少个元素。
具体例子:
数组:
[7, 5, 6, 4, 3, 2, 8]分析第 2 个位置(值为 5):
- 包含 5 的递减序列:
[7, 5]→ 长度 2[5]→ 长度 1[7, 5, 6]→ 不是递减(5 < 6)❌[5, 6]→ 不是递减 ❌- 最长的只有
[7, 5],长度是 2- 所以第 2 个位置的答案是 2
再看第 4 个位置(值为 4):
- 包含 4 的递减序列:
[6, 4]→ 长度 2[4]→ 长度 1[6, 4, 3]→ 长度 3[6, 4, 3, 2]→ 长度 4 ✅ 最长![4, 3]→ 长度 2[4, 3, 2]→ 长度 3- 最长的是
[6, 4, 3, 2],长度是 4- 所以第 4 个位置的答案是 4
总结:
输入一个数组,输出一个同样长度的数组,其中第 个数表示:原数组中第 个元素所在的最长连续递减子序列的长度。
💡 最终感悟:
所以我感觉这道题的难点在于题目太绕了,考验语文功底!😅
题目用了"最高的连续递减积木塔的一部分的最大高度"这种绕口令式的表达,让很多人(包括我)一看就懵了。但实际上,一旦理解了题意,这道题非常简单。
3. 题解代码 📝
3.1 我的解法
💡 理解了题目其实很简单,题解就不过多解释了
n = int(input())
blocks = list(map(int, input().split()))
# 存储所有连续递减段
segments = []
# 当前正在构建的递减段
current_segment = [blocks[0]]
for height in blocks[1:]:
# 如果比当前段最后一个小,就加入
if height < current_segment[-1]:
current_segment.append(height)
# 否则结束当前段,新开一段
else:
segments.append(current_segment)
current_segment = [height]
# 把最后一段加进去
segments.append(current_segment)
# 输出每一段的长度(重复段长度次)
for seg in segments:
print(f"{len(seg)} " * len(seg), end="")
4. 总结 📝
4.1 本题要点回顾
题目本质:
把数组分割成若干个连续递减段,每个位置输出它所在段的长度。
解题关键:
关键点 说明 理解题意 "连续递减积木塔" = 连续递减子序列 核心观察 同一段内所有位置答案相同 算法思路 一次遍历找递减段,输出段长度
4.2 经验总结
做题心得:
- 读题要仔细:不要被"积木塔"这种比喻迷惑,抓住数学本质
- 样例很重要:通过样例反推题意,验证理解是否正确
- 简化问题:把绕口的题目描述转化成自己好理解的语言
最终评价:
这道题算法本身很简单,难点全在语文理解上!😂
希望以后出题人能说人话...
最后更新时间:2026-04-25