← 返回编程题库
coding-min-margin-haircut-bisect中等免费版2000ms未尝试

覆盖负债的最大统一抵押减值率:单调谓词下的二分搜索

Largest Uniform Collateral Haircut Covering a Liability via Bisection

开始编码

实现 solution(notionals: list[float], target: float) -> float。一家清算所持有 N = len(notionals) 个抵押资产,第 i 个资产的名义价值为 notionals[i] >= 0,并面临总额为 target 的负债。对所有资产施加同一个统一减值率 hh 取值范围 [0, 1],则资产 i 的减值后价值为 notionals[i] * (1 - h)。求最大h,使减值后的总抵押价值仍然覆盖负债:

sum(notionals) * (1 - h) >= target

谓词 feasible(h) 是关于 h 单调递减的,因此在 [0, 1] 上对最大可行 h 做二分搜索,绝对容差 1e-7。哨兵契约(不抛异常):若 target <= 0 返回 1.0(任意减值都可行);若 sum(notionals) < target 返回 0.0(连不减值也无法覆盖);若任一 notionals[i] 非有限或为负、或 target 非有限,返回 float("nan")

示例

solution([100.0, 100.0], 100.0) 返回 0.5。总抵押 200,负债 100,仍能覆盖负债的最大统一减值率为 h = 1 - 100/200 = 0.5solution([100.0, 50.0], 0.0) 返回 1.0:目标为零,故 [0, 1] 中任意 h 都可行,最大值是 1.0solution([10.0, 20.0], 100.0) 返回 0.0:总抵押 30 低于负债 100,连 h = 0(不减值)都覆盖不了——哨兵把答案钉在 0.0

区分形态是**对 h 在单调递减谓词下的二分搜索**。减值后总值 S * (1 - h) 是关于 h 的非增线性函数(每个 notional 非负),故 feasible(h) = S * (1 - h) >= target[0, 1] 上为真当且仅当 h 落在前缀 [0, h_max] 中——通过维持不变量 feasible(lo) 为真、feasible(hi) 为假,二分至 hi - lo < 1e-9 即可定位 h_max。非严格的 >= 把临界等式 S * (1 - h) == target 留在可行集内;突变成 > 会错处理 target = S 这条边界(此时唯一可行的是 h = 0,答案必须是 0.0,不能给出小于零的任何值)。以步长 1e-9 做网格扫描需评估谓词 10**9 次,立即 TLE。请优先走哨兵分支:target <= 0 -> 1.0S < target -> 0.0、非法输入(负的或非有限的 notional、非有限的 target)-> NaN;二分仅在严格正缓冲分支 0 < target < S 上运行。

详见 stubs/stub.py 的函数骨架。

实务背景

清算所的保证金覆盖检查是受清算交易所或中央对手方最基本的风控原语:给定参与方提交的抵押资产名义簿和该方所欠负债,最激进的统一减值政策能压到多大、却仍维持仓位被完全覆盖?答案直接喂给日内追加保证金、日终压力测试以及"若政府债减值率上调 5%"之类的危机情景仿真。本题理想化的"对总额做统一减值"版本存在闭式解 h = 1 - target / sum(notionals),但生产环境中处理资产类别特定减值、合格性上限和集中度限制的工具仍依赖单调谓词下二分的范式:谓词是不透明的(它会调用一个覆盖率仿真器),但相对减值率标量仍单调,因此二分能稳健落点,无需导数或闭式。本题刻意用最简版本来锁定算法形态——真正考察的是谓词方向、临界等式处理和哨兵契约下对不可行 / 退化输入的应对。这与到期收益率(在价格-收益率曲线上求根)和 IRR(在 NPV 上求根)有别——这是阈值搜索:找最大的 h,使一个是 / 否谓词仍回答"是"。

约束条件

  • 0 <= len(notionals) <= 10000;每个 notionals[i] 为有限浮点数且 notionals[i] >= 0;target 为有限浮点数(可正可负)
  • 输出是最大的统一减值率 h,h ∈ [0, 1],满足 sum(notionals) * (1 - h) >= target;若有任何可行 h,返回可行前缀的上确界
  • 哨兵契约(不抛异常):target <= 0 返回 1.0;sum(notionals) < target 返回 0.0;任一 notionals[i] 非有限或为负、或 target 非有限,返回 float('nan');空 notionals 列表的答案完全由 target 的符号决定
  • 输出为单个浮点数;比较器为 float,rel_tol = 1e-6、abs_tol = 1e-7、nan_equals_nan = true(NaN 是非法输入下的契约返回,不视作错误)
  • 参考解复杂度:O(N + log(1/eps)),其中 N = len(notionals)、eps = 1e-9;预先求和后内层谓词求值为 O(1)

样例

Case 1 · statement-example: half-cover at 50% haircut

输入: [[100,100],100]

期望: 0.5

总抵押 200,目标 100;最大统一减值 h 满足 200*(1-h) >= 100,即 h <= 0.5

Case 2 · statement-example: target zero gives full haircut

输入: [[100,50],0]

期望: 1

目标为 0,任意 h 都满足 sum*(1-h) >= 0;返回 1.0

Case 3 · statement-example: total below target returns zero

输入: [[10,20],100]

期望: 0

总抵押 30 < 目标 100,连 h=0(不减值)都覆盖不了,返回 0.0

最近提交

还没有提交记录。

编码区

实现 solution(...)。本地运行当前支持 Python 可见样例;服务端提交会运行可见样例和隐藏测试。

加载编辑器...
计时0:00

默认展示公开样例。点击「运行样例」后会在这里显示实际输出;点击「提交评测」会进入隐藏测试。

Case 1 · statement-example: half-cover at 50% haircut

输入: [[100,100],100]

期望: 0.5

总抵押 200,目标 100;最大统一减值 h 满足 200*(1-h) >= 100,即 h <= 0.5

Case 2 · statement-example: target zero gives full haircut

输入: [[100,50],0]

期望: 1

目标为 0,任意 h 都满足 sum*(1-h) >= 0;返回 1.0

Case 3 · statement-example: total below target returns zero

输入: [[10,20],100]

期望: 0

总抵押 30 < 目标 100,连 h=0(不减值)都覆盖不了,返回 0.0