本題是 2928 的數據範圍加大版本,暴力做法可以參考該題的 解題紀錄 ,但在本題中使用會 TLE 。
題意
給定兩個正整數 n n n 和 l i m i t limit l imi t 。
返回將 n n n 個糖果分配給 3 3 3 個小孩的總方式數,且每位小孩獲得的糖果不超過 l i m i t limit l imi t 。
限制條件
1 ≤ n ≤ 1 0 6 1 \leq n \leq 10^6 1 ≤ n ≤ 1 0 6
1 ≤ l i m i t ≤ 1 0 6 1 \leq limit \leq 10^6 1 ≤ l imi t ≤ 1 0 6
思路
方法一:優化枚舉 + 一重迴圈
前一題 2928 中的暴力解法顯然太過簡單粗暴,讓我們更進一步優化。首先,可以先確定 i i i 的範圍為 [ 0 , min ( limit , n ) ] [0, \min(\text{limit}, n)] [ 0 , min ( limit , n )] ,而此時 j + k = n − i j + k = n - i j + k = n − i
若 j + k = n − i > 2 × limit j + k = n - i > 2 \times \text{limit} j + k = n − i > 2 × limit ,則不管怎麼分配,j j j 和 k k k 兩者間必有一人獲得超過 limit \text{limit} limit 個糖果,因此不合法。
否則,則可以考慮 j j j 的範圍:
j j j 的最大值 m x = min ( n − i , limit ) mx = \min(n - i, \text{limit}) m x = min ( n − i , limit ) ,即將剩餘的糖果全部給 j j j ,但需滿足 j ≤ limit j \leq \text{limit} j ≤ limit 。
j j j 的最小值 m n = max ( 0 , n − i − limit ) mn = \max(0, n - i - \text{limit}) mn = max ( 0 , n − i − limit ) ,即將剩餘的糖果全部給 k k k ,但需滿足 k ≤ limit k \leq \text{limit} k ≤ limit 。
而當 i , j i, j i , j 皆確定後,k k k 也就確定了,因此可以得出此時 j j j 的範圍為 [ m n , m x ] [mn, mx] [ mn , m x ] ,有 m x − m n + 1 mx - mn + 1 m x − mn + 1 種分配方式。
如此一來,我們只需枚舉 i i i ,再根據 i i i 確定 j j j 的範圍,即可計算出答案。
複雜度分析
時間複雜度 O ( min ( limit , n ) ) O(\min(\text{limit}, n)) O ( min ( limit , n )) 。
空間複雜度 O ( 1 ) O(1) O ( 1 )
1 2 3 4 5 6 7 8 9 10 class Solution : def distributeCandies (self, n: int , limit: int ) -> int : ans = 0 for i in range (min (limit, n) + 1 ): if n - i > 2 * limit: continue mx = min (n - i, limit) mn = max (0 , n - i - limit) ans += mx - mn + 1 return ans
1 2 3 4 5 6 7 8 9 10 11 12 13 class Solution {public : int distributeCandies (int n, int limit) { int ans = 0 , mx, mn; for (int i = 0 ; i <= min (limit, n); i++) { if (n - i > 2 * limit) continue ; mx = min (n - i, limit); mn = max (0 , n - i - limit); ans += mx - mn + 1 ; } return ans; } };
方法二:排容原理
除了枚舉之外,也能用 排容原理 計算,即計算所有可能的組合數,再扣除不合法的情況,若有重複扣除的情況,則需要再加回來,以此類推。
而將 n n n 個糖果分配給 3 3 3 個小孩的任意方式數為 H n 3 = ( n + 2 2 ) H^3_n = \binom{n+2}{2} H n 3 = ( 2 n + 2 ) ,即 C ( n + 2 , 2 ) C(n+2, 2) C ( n + 2 , 2 ) ,可以用 隔板法 思考。而我們可以用此方式繼續計算出不合法的情況,即至少一人拿到超過 limit \text{limit} limit 個糖果的情況,以及至少兩人拿到超過 limit \text{limit} limit 個糖果的情況。
初始化答案為 H n 3 = ( n + 2 2 ) H^3_n = \binom{n+2}{2} H n 3 = ( 2 n + 2 ) 。
若 n ≥ limit + 1 n \geq \text{limit} + 1 n ≥ limit + 1 ,則在所有方案中,存在某些方案使得至少一人拿到超過 limit \text{limit} limit 個糖果,計算這種情況的方式數:
計算方式為先將 l i m i t + 1 limit + 1 l imi t + 1 個糖果分給其中一人,則剩下 n − ( l i m i t + 1 ) n - (limit + 1) n − ( l imi t + 1 ) 個糖果,則有 H n − ( l i m i t + 1 ) 3 = ( n − ( l i m i t + 1 ) + 2 2 ) = ( n − l i m i t + 1 2 ) H^3_{n-(limit+1)} = \binom{n-(limit+1)+2}{2} = \binom{n-limit+1}{2} H n − ( l imi t + 1 ) 3 = ( 2 n − ( l imi t + 1 ) + 2 ) = ( 2 n − l imi t + 1 ) 種分配方式。
由於有三個小孩,選擇 1 1 1 個小孩的方法數有 ( 3 1 ) = 3 \binom{3}{1} = 3 ( 1 3 ) = 3 種,因此有 3 × H n − ( l i m i t + 1 ) 3 = 3 × ( n − l i m i t + 1 2 ) 3 \times H^3_{n-(limit+1)} = 3 \times \binom{n-limit+1}{2} 3 × H n − ( l imi t + 1 ) 3 = 3 × ( 2 n − l imi t + 1 ) 種分配方式。
將答案減去 3 × ( n − l i m i t + 1 2 ) 3 \times \binom{n-limit+1}{2} 3 × ( 2 n − l imi t + 1 ) 。
若 n ≥ 2 × ( limit + 1 ) n \geq 2 \times (\text{limit} + 1) n ≥ 2 × ( limit + 1 ) ,則在所有方案中,存在某些方案使得至少兩人拿到超過 limit \text{limit} limit 個糖果,計算這種情況的方式數:
計算方式為先將 2 × ( l i m i t + 1 ) 2 \times (limit + 1) 2 × ( l imi t + 1 ) 個糖果分給其中兩人,則剩下 n − 2 × ( l i m i t + 1 ) n - 2 \times (limit + 1) n − 2 × ( l imi t + 1 ) 個糖果,則有 H n − 2 × ( l i m i t + 1 ) 3 = ( n − 2 × ( l i m i t + 1 ) + 2 2 ) = ( n − 2 × l i m i t 2 ) H^3_{n-2 \times (limit+1)} = \binom{n-2 \times (limit+1)+2}{2} = \binom{n-2 \times limit}{2} H n − 2 × ( l imi t + 1 ) 3 = ( 2 n − 2 × ( l imi t + 1 ) + 2 ) = ( 2 n − 2 × l imi t ) 種分配方式。
由於有三個小孩,選擇 2 2 2 個小孩的方法數有 ( 3 2 ) = 3 \binom{3}{2} = 3 ( 2 3 ) = 3 種,因此有 3 × H n − 2 × ( l i m i t + 1 ) 3 = 3 × ( n − 2 × l i m i t 2 ) 3 \times H^3_{n-2 \times (limit+1)} = 3 \times \binom{n-2 \times limit}{2} 3 × H n − 2 × ( l imi t + 1 ) 3 = 3 × ( 2 n − 2 × l imi t ) 種分配方式。
將答案加上 3 × ( n − 2 × l i m i t 2 ) 3 \times \binom{n-2 \times limit}{2} 3 × ( 2 n − 2 × l imi t ) 。
若 n ≥ 3 × ( limit + 1 ) n \geq 3 \times (\text{limit} + 1) n ≥ 3 × ( limit + 1 ) ,則在所有方案中,存在某些方案使得三人皆拿到超過 limit \text{limit} limit 個糖果,計算這種情況的方式數:
計算方式為先將 3 × ( l i m i t + 1 ) 3 \times (limit + 1) 3 × ( l imi t + 1 ) 個糖果分給三人,則剩下 n − 3 × ( l i m i t + 1 ) n - 3 \times (limit + 1) n − 3 × ( l imi t + 1 ) 個糖果,則有 H n − 3 × ( l i m i t + 1 ) 3 = ( n − 3 × ( l i m i t + 1 ) + 2 2 ) = ( n − 3 × l i m i t − 1 2 ) H^3_{n-3 \times (limit+1)} = \binom{n-3 \times (limit+1)+2}{2} = \binom{n-3 \times limit-1}{2} H n − 3 × ( l imi t + 1 ) 3 = ( 2 n − 3 × ( l imi t + 1 ) + 2 ) = ( 2 n − 3 × l imi t − 1 ) 種分配方式。
由於有三個小孩,選擇 3 3 3 個小孩的方法數有 ( 3 3 ) = 1 \binom{3}{3} = 1 ( 3 3 ) = 1 種,因此有 H n − 3 × ( l i m i t + 1 ) 3 = ( n − 3 × l i m i t − 1 2 ) H^3_{n-3 \times (limit+1)} = \binom{n-3 \times limit-1}{2} H n − 3 × ( l imi t + 1 ) 3 = ( 2 n − 3 × l imi t − 1 ) 種分配方式。
將答案減去 ( n − 3 × l i m i t − 1 2 ) \binom{n-3 \times limit-1}{2} ( 2 n − 3 × l imi t − 1 ) 。
此外,當 n > 3 × limit n > 3 \times \text{limit} n > 3 × limit 時,必有至少一人拿到超過 limit \text{limit} limit 個糖果,不存在合法情況。對於這種情況,可以直接返回 0 0 0 。因此上面的第 3 3 3 點其實可以省略。
複雜度分析
時間複雜度 O ( 1 ) O(1) O ( 1 ) 。
空間複雜度 O ( 1 ) O(1) O ( 1 )
1 2 3 4 5 6 7 8 9 10 11 12 class Solution : def distributeCandies (self, n: int , limit: int ) -> int : if n > 3 * limit: return 0 ans = comb(n + 2 , 2 ) if n >= (limit + 1 ): ans -= 3 * comb(n - limit + 1 , 2 ) if n >= 2 * (limit + 1 ): ans += 3 * comb(n - 2 * limit, 2 ) return ans
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 class Solution {public : int calc (int x) { if (x < 0 ) return 0 ; return x * (x - 1 ) / 2 ; } int distributeCandies (int n, int limit) { if (n > 3 * limit) return 0 ; int ans = calc (n+2 ); ans -= 3 * calc (n - limit + 1 ); ans += 3 * calc (n - 2 * limit); return ans; } };
寫在最後
Cover photo is generated by @ゴリラの素材屋さん , thanks for their work!