计算合法分配方案数的方法:
合法方案数(所有小朋友糖果数 ≤ limit) = 总方案数 - 非法方案数(至少一个小朋友糖果数 > limit)
-
总方案数(不考虑limit限制): 将n个小球分配给3个不同盒子 相当于在n+2个位置中选择2个位置放置隔板 公式:C(n+2, 2)
-
非法方案数(至少一个小朋友糖果数 > limit): 采用容斥原理计算:
-
单个小朋友超过limit的情况(集合A,B,C): 已分配(limit+1)个糖果,剩余n-(limit+1)个 每种情况方案数:C(n-(limit+1)+2, 2)
-
两个小朋友同时超过limit的情况(集合A∩B,B∩C,C∩A): 已分配2*(limit+1)个糖果,剩余n-2*(limit+1)个 每种情况方案数:C(n-2*(limit+1)+2, 2)
-
三个小朋友同时超过limit的情况(集合A∩B∩C): 已分配3*(limit+1)个糖果,剩余n-3*(limit+1)个 方案数:C(n-3*(limit+1)+2, 2)
-
最终计算公式: C(n+2,2) - 3C(n-(limit+1)+2,2) + 3C(n-2*(limit+1)+2,2) - C(n-3*(limit+1)+2,2)
class Solution {
public:
/*
合法方案数(所有小朋友分到的糖果数 < = limit) = 不考虑limit的所有方案数 - 不合法方案数(至少有一个小朋友分到的糖果数 > limit)
不考虑limit的所有方案数:
n个小球放到3个有区别的盒子中
n + 2 个位置,2个放隔板,剩下n个放小球
C(n + 2,2)
不合法方案数(至少有一个小朋友分到的糖果数 > limit)
集合A:甲分到的糖果数 > limit(乙丙分到的不管) 已经分出去了limit + 1 剩下n - limit - 1分给3个小朋友
集合B:乙分到的糖果数 > limit(甲丙分到的不管)
集合C:丙分到的糖果数 > limit(甲乙分到的不管)
集合A∩B:甲乙分到的糖果数 > limit(丙分到的不管) 已经分出去了2*(limit + 1) 剩下n - 2*(limit + 1)分给3个小朋友
集合B∩C:乙丙分到的糖果数 > limit(甲分到的不管)
集合C∩A:甲丙分到的糖果数 > limit(乙分到的不管)
集合A∩B∩C:甲乙丙分到的糖果数 > limit 已经分出去了3*(limit + 1) 剩下n - 3*(limit + 1)分给3个小朋友
A + B + C - A∩B - B∩C - A∩C + (A∩B∩C)
C(n + 2,2) - 3 * C(n - limit - 1 + 2,2) + 3 * C(n - 2*limit - 2 + 2,2) - C(n - 3*(limit + 1) + 2,2)
*/
int distributeCandies(int n, int limit) {
auto c2 = [&](this auto && c2,int n)->int{
if (n > 1) {
return n * (n - 1) / 2;
}
return 0;
};
return c2(n + 2) - 3 * c2(n - limit - 1 + 2) + 3 * c2(n - 2*limit - 2 + 2) - c2(n - 3*(limit + 1) + 2);
}
};
时间复杂度:O(1)
空间复杂度:O(1)