净值分桶 —— 在每段长度上限下,最少的严格正和覆盖块
Tear-Sheet Bucketing — Fewest Strictly-Positive-Sum Cover Chunks With Per-Block Length Cap
开始编码实现 solution(returns: list[float], max_len: int) -> int。给定长度为 N 的每期收益序列与每段长度上限 max_len,将其划分为连续、不重叠的若干段,覆盖整个数组([0, N) 中每个下标恰属于一个段),并使每一段同时满足:
- 段和严格大于
0.0; - 段长(元素个数)在
[1, max_len]范围内。
返回可达成的最小段数。若不存在这样的覆盖划分,返回 -1。空输入(N == 0)无视 max_len 返回 0。
示例矩阵:
solution([1.5], 1)返回1(单段,和1.5 > 0,长度1 <= 1)。solution([0.0], 1)返回-1(唯一段和0.0不严格大于0)。solution([1.0, 1.0, 1.0], 1)返回3(max_len = 1强制每段单元素,三段各1.0)。solution([1.0, 1.0, 1.0], 2)返回2(例:[1.0] | [1.0, 1.0],段和1.0、2.0)。solution([1.0, 1.0, 1.0], 3)返回1(整段单块和3.0)。solution([2.0, -3.0, 4.0, -1.0], 2)返回-1(不存在每段长度<= 2的全正分割)。
例
solution([3.0, -1.0, 2.0, -1.0, 3.0], 2) 返回 3。max_len = 2 禁止整段(长度 5)以及长 3、4 的段,只剩长 1 与长 2 的块。一组最优解 [3.0] | [-1.0, 2.0] | [-1.0, 3.0]:段和 3.0、1.0、2.0 全部严格正,共三段。两段覆盖不可能,因为两个长度 <= 2 的块加起来至多 4 < 5。对比 solution([3.0, -1.0, 2.0, -1.0, 3.0], 5) 返回 1(整段和 6.0 > 0,单块)。
实践背景
研究台把长跨度的日收益序列以"赢段"长条形式渲染净值分桶图:每根绿条标签显示该段累计收益。合规对分桶施加两条规则:每根可视化的绿条严格正和(零和绿条标签为"赢段"会误导评审),且任何一根绿条最多跨 max_len 个日历期(这是粒度规则 —— 即便策略全程稳定盈利,评审也不希望看到一根横跨整年的大绿块,而要更细粒度的日内/月内细节)。在两条规则下,研究台希望用最少的绿条覆盖整条序列端到端,因为三根大绿条比三十根小绿条更能讲清故事;空缺不被允许,因为每一期都必须被某根绿条吃到。当两条规则下都无法覆盖(典型是某段持续回撤无法被分解成有界长的赢段块),研究台直接不渲染 —— 在本题里编码为 -1 哨兵。段和严格大于 0 的比较器是有意为之:和恰为 0.0 的段在任何诚实意义上都不算"赢段"。
实现细节由 stubs/stub.py 提供。
约束条件
- 0 <= N <= 1500,其中 N 为 solution(returns, max_len) 的 returns 输入长度
- 1 <= max_len <= 1500;每段最多包含 max_len 个连续元素(段长取值范围 [1, max_len])
- 每个 returns[i] 为有限浮点数,-1e6 <= returns[i] <= 1e6(每期收益率,**不是**价格)
- 段合格当且仅当其和**严格大于** `0.0`;段和等于 `0.0` 的段**不**合格(比较器为 `>`,不是 `>=`)
- 返回类型为 int。分割必须**覆盖**整个数组 —— `[0, N)` 中每个下标恰属于一个段,段间连续不重叠。空 returns 必须返回 0;若两条约束下不存在合法覆盖分割,返回 -1(哨兵)
样例
Case 1 · statement-example: max_len=2 forces 3 segments on alternating returns
输入: [[3,-1,2,-1,3],2]
期望: 3
一组最优 [3.0]|[-1.0,2.0]|[-1.0,3.0],段和 3.0/1.0/2.0 全严格正;2 段不可达,因两段长度<=2 至多覆盖 4<5 元素。
Case 2 · statement-example: max_len=5 collapses to single segment whole-array
输入: [[3,-1,2,-1,3],5]
期望: 1
max_len 大于等于 N,约束失效;整段和 6.0>0,单块覆盖。
Case 3 · statement-example: single positive element max_len=1 returns 1
输入: [[1.5],1]
期望: 1
单元素 1.5 > 0,构成一段。
Case 4 · statement-example: single zero element returns -1 (strict comparator)
输入: [[0],1]
期望: -1
唯一段和 0.0,不严格大于 0,不合格;返回 -1。
Case 5 · statement-example: empty input returns 0 regardless of max_len
输入: [[],7]
期望: 0
空数组被零段平凡覆盖,返回 0。
Case 6 · statement-example: max_len=2 with negative-dominated array returns -1
输入: [[2,-3,4,-1],2]
期望: -1
不存在每段长度<=2 的全严格正分割;任何切法都至少一段非正。
Case 7 · typical: max_len=1 all positive elements forces N segments
输入: [[1,1,1,1],1]
期望: 4
Case 8 · typical: max_len=2 monotone positive yields ceil(n/2)
输入: [[0.1,0.2,0.3,0.4],2]
期望: 2
Case 9 · typical: max_len equals N positive total -> 1
输入: [[10,-1,-1,-1,-1],5]
期望: 1
最近提交
还没有提交记录。
编码区
实现 solution(...)。本地运行当前支持 Python 可见样例;服务端提交会运行可见样例和隐藏测试。
默认展示公开样例。点击「运行样例」后会在这里显示实际输出;点击「提交评测」会进入隐藏测试。
Case 1 · statement-example: max_len=2 forces 3 segments on alternating returns
输入: [[3,-1,2,-1,3],2]
期望: 3
一组最优 [3.0]|[-1.0,2.0]|[-1.0,3.0],段和 3.0/1.0/2.0 全严格正;2 段不可达,因两段长度<=2 至多覆盖 4<5 元素。
Case 2 · statement-example: max_len=5 collapses to single segment whole-array
输入: [[3,-1,2,-1,3],5]
期望: 1
max_len 大于等于 N,约束失效;整段和 6.0>0,单块覆盖。
Case 3 · statement-example: single positive element max_len=1 returns 1
输入: [[1.5],1]
期望: 1
单元素 1.5 > 0,构成一段。
Case 4 · statement-example: single zero element returns -1 (strict comparator)
输入: [[0],1]
期望: -1
唯一段和 0.0,不严格大于 0,不合格;返回 -1。
Case 5 · statement-example: empty input returns 0 regardless of max_len
输入: [[],7]
期望: 0
空数组被零段平凡覆盖,返回 0。
Case 6 · statement-example: max_len=2 with negative-dominated array returns -1
输入: [[2,-3,4,-1],2]
期望: -1
不存在每段长度<=2 的全严格正分割;任何切法都至少一段非正。
Case 7 · typical: max_len=1 all positive elements forces N segments
输入: [[1,1,1,1],1]
期望: 4
Case 8 · typical: max_len=2 monotone positive yields ceil(n/2)
输入: [[0.1,0.2,0.3,0.4],2]
期望: 2
Case 9 · typical: max_len equals N positive total -> 1
输入: [[10,-1,-1,-1,-1],5]
期望: 1