You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

CodeChef LOWSUM问题:双循环优化逻辑疑问求解

拆解这段优化代码的剪枝逻辑

嘿,我来帮你搞懂这两行代码的作用——它们是整个优化的核心,本质是剪掉那些不可能成为目标第M小和的组合(这里代码默认目标是第10000小的和,对应10001这个数),避免暴力生成所有k²个组合(当k=1e4时,1e8个元素根本处理不动)。

先提前说个容易混淆的点:代码里的变量n是临时计算值,和问题里要找的“第n小的和”的n重名了,我后面会用M指代目标的“第M小”(这里M=10000)。

1. 为什么要写 n=10001/i?

首先,代码开头已经把数组a和b从小到大排序了,这是优化的基础。基于有序性,我们可以得出一个关键结论:

对于排序后的a[i](第i小的元素)和b[j](第j小的元素),所有a[x]+b[y](x≤i,y≤j)的和都≤a[i]+b[j],这样的组合一共有i*j个。

假设我们要找第M=10000小的和,那如果i*j > M,说明a[i]+b[j]至少比i*j个和要大,它肯定排不到前10000名里,完全没必要加入候选集合vc。

反过来,我们只需要保留j ≤ M/i的组合,这样i*j ≤ M,这些组合才有可能成为前M小的和的候选。代码里用10001/i而不是10000/i,是为了适配整数除法的特性:

  • 当i能整除10000时,10001/i和10000/i结果一致;
  • 当i不能整除10000时,10001/i等于ceil(10000/i),确保不会漏掉刚好i*j=10000的临界组合。

2. 为什么要写 ind=min(k,n)?

这一步是做边界保护:b数组总共只有k个元素,就算n计算出来比k大(比如当i=1时,10001/1=10001,但k最多是10000),我们也不可能取到b的第10001个元素,所以必须把j的上限限制在数组的实际长度k以内,避免数组越界。

用你的示例验证一下

你的示例:A=[1,2,3],B=[4,5,6],要找第4小的和(M=4)。按照这个逻辑:

  • 当i=1时,n=(4+1)/1=5,ind=min(3,5)=3,所以j取1-3,加入和:5、6、7;
  • 当i=2时,n=(4+1)/2=2(整数除法),ind=min(3,2)=2,所以j取1-2,加入和:6、7;
  • 当i=3时,n=(4+1)/3=1,ind=min(3,1)=1,所以j取1,加入和:7;

最终候选集合是[5,6,7,6,7,7],排序后是[5,6,6,7,7,7],第4小的就是7,和示例结果一致。而暴力法会生成9个元素,这里剪枝掉了3个肯定排不上号的组合(2+6=8、3+5=8、3+6=9),效率提升明显。

这个优化的性能优势

当k=10000时,暴力法会生成1e8个元素,完全无法处理;而用这个优化,候选元素的总数是Σ(min(k, 10001/i))(i从1到10000),计算下来大概是1e4乘以调和级数前1e4项的和(约9.7),总候选数大概1e5左右——排序1e5个元素比处理1e8个元素快了好几个数量级。

内容的提问来源于stack exchange,提问作者N Nair

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 07:18:58