codeforces-go 仓库题解深度解析:用隔板法与容斥原理 O(1) 求解「分糖果给小朋友 II」

发布时间:2026/10/3 17:39:17
codeforces-go 仓库题解深度解析:用隔板法与容斥原理 O(1) 求解「分糖果给小朋友 II」 科学计算【免费下载链接】codeforces-go算法竞赛模板库 by 灵茶山艾府 项目地址https://gitcode.com/GitHub_Trending/co/codeforces-go点击查看免费下载导读本文以 leetcode/biweekly/117/b/README.md 为骨架完整还原力扣第 117 场双周赛第二题「分糖果给小朋友 IIDistribute Candies Among Children II」的数学解法先用隔板法统计无上限约束的所有分配方案数再用容斥原理剔除至少一个小朋友分到的糖果超过 limit的非法方案最终得到一个可直接套用的组合数公式。读完本文你将掌握无区别物体放入有区别盒子的组合计数建模、三集合容斥的逐步推导技巧以及如何在 codeforces-go 仓库中一行代码落地该公式并借助仓库自带的测试框架验证正确性。一、问题背景题目在仓库中的位置与题面重述该题解位于仓库的 leetcode/biweekly/117/b/README.md对应的可运行实现是 leetcode/biweekly/117/b/b.go。从测试文件 b_test.go 末尾的注释可以确认本题对应力扣题目distribute-candies-among-children-ii。题面可重述为有 $n$ 颗无区别的糖果要全部分给 $3$ 个有区别的小朋友 $A,B,C$且每个小朋友分到的糖果数不超过$\textit{limit}$ 颗求合法的分配方案数。值得一提的是同一场双周赛的第一题「分糖果给小朋友 I」共享完全相同的思路第一题实现位于 leetcode/biweekly/117/a/a.go。两版代码的唯一差别在于返回值类型I 版的 $n$ 范围较小返回intII 版的 $n$ 范围更大返回int64以避免组合数运算中间结果溢出。这也是同一个数学模型因数据范围不同需要调整数值类型的典型工程案例。二、问题建模转化为小球入盒的组合计数把 $n$ 颗无区别糖果看成 $n$ 个无区别的小球把 3 个小朋友看成 3 个有区别的盒子。合法方案数即为把 $n$ 个无区别小球放入 3 个有区别盒子允许空盒且每个盒子的小球数不超过 $\textit{limit}$ 的方案数。求解思路采用正难则反$$ \text{合法方案数} \text{所有方案数} - \text{不合法方案数} $$其中不合法指至少一个小朋友分到的糖果超过 $\textit{limit}$。三、第一步用隔板法求所有方案数在没有 $\textit{limit}$ 限制时问题退化为经典组合计数$n$ 个无区别小球放入 $3$ 个有区别盒子、允许空盒的方案数。隔板法是标准工具把 $n$ 个球排成一列在它们之间及两端共 $n1$ 个空隙中插入 $2$ 个隔板用隔板把球分成三段依次对应三个盒子。等价地可理解为 $n$ 个球与 $2$ 个隔板共 $n2$ 个位置从中选出 $2$ 个位置放隔板其余位置放球第一个隔板之前的球进第 1 个盒子第一个隔板与第二个隔板之间的球进第 2 个盒子第二个隔板之后的球进第 3 个盒子。因此所有方案数为$$ \binom{n2}{2} $$隔板法天然覆盖了空盒情形隔板可以放在最左端第 1 个盒子为空、最右端第 3 个盒子为空两个隔板也可以相邻第 2 个盒子为空均对应一种合法摆放方式无需单独讨论。边界提示组合数 $\binom{n2}{2}$ 恒有意义$n \geqslant 0$但后续容斥项中的参数可能变成负数需要借助当 $x 2$ 时 $\binom{x}{2}0$的约定来统一处理详见第六节。四、第二步用容斥原理逐层统计不合法方案设 $A,B,C$ 分别表示小朋友 $A/B/C$ 分到的糖果超过 $\textit{limit}$这一事件不合法方案数即 $|A \cup B \cup C|$用容斥原理展开为$$ |A \cup B \cup C| |A||B||C| - |A\cap B|-|A\cap C|-|B\cap C| |A\cap B\cap C| $$4.1 至少一个小朋友超过 limit$|A||B||C|$先只看 $A$。若 $A$ 分到的糖果超过 $\textit{limit}$则先固定分给他 $\textit{limit}1$ 颗剩余 $n-(\textit{limit}1)$ 颗糖果仍然可以随意分给 3 个小朋友包括继续分给 $A$这一点至关重要下文单独强调于是方案数为$$ \binom{n-(\textit{limit}1)2}{2} \binom{n-\textit{limit}1}{2} $$$B$、$C$ 的情形完全对称三者相加得 $3\cdot\binom{n-\textit{limit}1}{2}$。由于这三个集合两两相交直接相加会重复统计至少两个小朋友超过 limit的方案故需进入下一步扣除。⚠易错点固定分给 $A$ 的 $\textit{limit}1$ 颗之后剩余糖果依然可以继续分给 $A$。也就是说先分给他 limit1 颗只是为了保证该方案至少超过 limit 一次并不代表总共只分给他 limit1 颗遗漏这一点会漏计大量方案。4.2 至少两个小朋友超过 limit$|A\cap B||A\cap C||B\cap C|$只看 $A$ 和 $B$。若两者都超过 $\textit{limit}$先固定分给他们各 $\textit{limit}1$ 颗即共 $2\cdot(\textit{limit}1)$ 颗剩余 $n-2\cdot(\textit{limit}1)$ 颗随意分配给 3 人$C$ 是否超过 limit 不予关注方案数为$$ \binom{n-2\cdot(\textit{limit}1)2}{2} \binom{n-2\cdot\textit{limit}}{2} $$三组配对 $(A,B),(A,C),(B,C)$ 对称相加得 $3\cdot\binom{n-2\cdot\textit{limit}}{2}$。但这里又重复统计了三个小朋友均超过 limit的方案三个集合的交集被三组两两交集各统计一次因此还需要最后一步修正。4.3 三个小朋友均超过 limit$|A\cap B\cap C|$先固定分给三人共 $3\cdot(\textit{limit}1)$ 颗剩余 $n-3\cdot(\textit{limit}1)$ 颗随意分配方案数为$$ \binom{n-3\cdot(\textit{limit}1)2}{2} \binom{n-3\cdot\textit{limit}-1}{2} $$4.4 容斥汇总将各层按奇加偶减合并不合法方案数为$$ 3\cdot\binom{n-\textit{limit}1}{2} - 3\cdot\binom{n-2\cdot\textit{limit}}{2} \binom{n-3\cdot\textit{limit}-1}{2} $$再用所有方案数减去它即得最终答案公式$$ \boxed{\binom{n2}{2} - 3\cdot\binom{n-\textit{limit}1}{2} 3\cdot\binom{n-2\cdot\textit{limit}}{2} - \binom{n-3\cdot\textit{limit}-1}{2}} $$这也印证了题解中至少一个 − (至少两个 − 三个) 至少一个 − 至少两个 三个的归纳三个集合的容斥最终表现为四个组合数的交错和其本质就是标准的 3 集合容斥展开。五、最终公式的多语言实现题解为 Python3、Java、C、C、Go、JavaScript、Rust 提供了完全同构的七份实现。其公共要点是定义辅助函数 $c_2(x)$$$ c_2(x)\begin{cases}\frac{x(x-1)}{2} x1\ 0 x\leqslant 1\end{cases} $$即当 $x2$ 时组合数 $\binom{x}{2}0$——这正是处理剩余糖果为负这类越界参数的关键。以仓库实际使用的 Go 实现为例与 b.go 逐行一致func c2(n int) int64 { if n 2 { return 0 } return int64(n) * int64(n-1) / 2 } func distributeCandies(n int, limit int) int64 { return c2(n2) - 3*c2(n-limit1) 3*c2(n-2*limit) - c2(n-3*limit-1) }Python 参考实现同样简洁def c2(n: int) - int: return n * (n - 1) // 2 if n 1 else 0 class Solution: def distributeCandies(self, n: int, limit: int) - int: return c2(n 2) - 3 * c2(n - limit 1) 3 * c2(n - 2 * limit) - c2(n - 3 * limit - 1)其余语言Java/C/C/JavaScript/Rust的写法与上述完全等价仅语法与整数溢出保护策略不同C/C 使用long longJava 使用longRust 显式做as i64转换目的都是在乘法n*(n-1)前提升到 64 位整数避免中间结果溢出。六、复杂度分析与数值边界时间复杂度$\mathcal{O}(1)$——每个组合数由一次乘法、一次减法、一次除法直接算出不依赖 $n$ 的大小。空间复杂度$\mathcal{O}(1)$——仅使用常数个变量。数值边界方面需要注意两点负数参数的组合数约定当 $n$ 较小时容斥项如 $n-2\cdot\textit{limit}$ 甚至 $n-3\cdot\textit{limit}-1$ 会变成负数此时约定 $\binom{x}{2}0$由c2的n 2分支统一处理。例如 $n5, \textit{limit}2$ 时后两项参数分别为 $1$ 和 $-2$均返回 0。整数类型选择$n$ 可达到 $10^6$ 量级时$n^2$ 已达 $10^{12}$超过 32 位int上限因此 II 版题解b.go的c2返回int64这正是它与 I 版a.go返回int的唯一实现差异。七、仓库内的测试验证从公式到可运行用例该仓库为每道题配套了题解 实现 输入数据 测试四件套本题的验证闭环如下实现b.go 提供distributeCandies函数输入数据b.txt 按每 3 行一组存放测试用例2 个输入参数 1 个预期输出共两组n5, limit2期望输出3n3, limit3期望输出10。测试入口b_test.go 调用testutil.RunLeetCodeFuncWithFile(t, distributeCandies, b.txt, targetCaseNum)驱动验证。可手工验算两组数据印证公式正确性$n5,\ \textit{limit}2$$\binom{7}{2}-3\binom{4}{2}3\binom{1}{2}-\binom{-2}{2}21-180-03$ ✔枚举可得 3 种分配$(3,1,1)$ 的三组排列$n3,\ \textit{limit}3$每人上限 3 颗而总共只有 3 颗所有方案天然合法$\binom{5}{2}10$ ✔即 $xyz3$ 的非负整数解个数。测试驱动层位于 leetcode/testutil/leetcode.go 的RunLeetCodeFuncWithFile它读取b.txt按函数签名NumIn NumOut行一组解析输入与期望输出再用反射逐组调用被测函数并比对结果而 RunLeetCodeFuncWithExamples 会在运行单个用例后自动继续跑完全部用例并支持-1表示最后一个用例、检测超时TLE等细节是仓库所有 LeetCode 题解共用的通用测试设施。若在 leetcode/biweekly/117/b 目录执行go test即可一键跑通上述全部验证。八、思维延伸从分糖果到更广的容斥应用本题是三集合容斥 隔板法的教科书级组合隔板法负责无约束计数容斥负责处理上界约束二者各司其职。同场双周赛的第三题 README.md 是同一套思想的另一形态——统计恰好包含 1 个l、1 个t、2 个e的长度为 $n$ 的字符串个数同样以正难则反构造三个违规条件并用容斥展开最终化简为四个快速幂项的交错和$\mathcal{O}(\log n)$。对照阅读这两份题解可以清晰看到容斥原理这一数学工具的两种典型落地形态一者是组合数求和一者是快速幂求和。若想在类似题目中复用本文方法建议遵循三步套路先建模为无区别物体入有区别盒子再写出无约束方案数最后按违规条件个数分层套用容斥把每一层先固定越界部分、剩余任意分配的计数模式即 $\binom{\cdot}{2}$提炼出来。总结本文从 leetcode/biweekly/117/b/README.md 出发完整推导了分糖果给小朋友 II的 $\mathcal{O}(1)$ 公式隔板法给出基准 $\binom{n2}{2}$三集合容斥给出修正项 $-3\binom{n-\textit{limit}1}{2}3\binom{n-2\textit{limit}}{2}-\binom{n-3\textit{limit}-1}{2}$并给出了 Python/Java/C/C/Go/JavaScript/Rust 七种语言的等价实现。同时结合仓库内 b.go、b.txt、b_test.go 与通用测试框架 leetcode/testutil/leetcode.go用两组可运行用例验证了公式的正确性。理解隔板法计数 容斥修正这套组合拳即可举一反三地解决带个体上限的整数拆分计数这一大类组合问题。赞分享科学计算【免费下载链接】codeforces-go算法竞赛模板库 by 灵茶山艾府 项目地址https://gitcode.com/GitHub_Trending/co/codeforces-go点击查看免费下载相关推荐分钱给最多孩子双周赛 100 首题O(1) 解法数学推导、四语言实现与 codeforces-go 仓库工程实践分钱给最多孩子双周赛 100 首题O 1 解法数学推导、四语言实现与 codeforces go 仓库工程实践 本篇文章以灵茶山艾府算法竞赛模板库 cod科学计算cdp高级用法如何实现Headless Chrome的并发控制cdp高级用法如何实现Headless Chrome的并发控制 在现代Web开发和自动化测试中Headless Chrome已成为不可或缺的工具。而使用GoLeetCode-Go 题解 135Candy 分发糖果的双向贪心扫描算法深度解析LeetCode Go 题解 135Candy 分发糖果的双向贪心扫描算法深度解析 导读 LeetCode 第 135 题「Candy分发糖果」是一道经示例工程上一篇Comprehensive Rust 精讲可变静态变量static mut为何需要 unsafe以及如何在 no_std 低层代码中安全使用下一篇将 REST API 通过 Azure API Management 发布为 MCP Server从创建、限流策略到 Copilot Agent 调用全指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考