To solve this problem, we need to find the number of valid k-length subsets of an array such that the sum of the subset is divisible by k. The solution leverages modular arithmetic and dynamic programming to efficiently compute the result.
Approach
- Modular Arithmetic: Convert each element to its remainder when divided by k. This reduces the problem to finding subsets where the sum of remainders is divisible by k.
- Count Remainders: Count the number of elements for each remainder (0 to k-1).
- Dynamic Programming: Use a DP table to track the number of ways to choose elements such that the sum of their remainders modulo k is a specific value and the subset size is exactly k.
- Combinatorial Calculations: Precompute factorials and their modular inverses to efficiently calculate combinations (n choose x) for small x (up to k).
Solution Code
MOD = 10**9 + 7
def count_valid_subsets(arr, k):
n = len(arr)
if k > n:
return 0 # Cannot choose k elements from a smaller array
# Step 1: Compute remainder counts
cnt = [0] * k
for num in arr:
r = num % k
cnt[r] += 1
# Step 2: Precompute factorials and inverse factorials up to k
max_x = k
fact = [1] * (max_x + 1)
for i in range(1, max_x + 1):
fact[i] = fact[i-1] * i % MOD
inv_fact = [1] * (max_x + 1)
inv_fact[max_x] = pow(fact[max_x], MOD-2, MOD)
for i in range(max_x -1, -1, -1):
inv_fact[i] = inv_fact[i+1] * (i+1) % MOD
# Step3: Dynamic Programming
# prev_dp[j][s] = number of ways to choose j elements with sum mod k = s
prev_dp = [[0]*k for _ in range(k+1)]
prev_dp[0][0] = 1
for r in range(k):
curr_cnt = cnt[r]
curr_dp = [[0]*k for _ in range(k+1)]
for j_prev in range(k+1):
for s_prev in range(k):
if prev_dp[j_prev][s_prev] == 0:
continue
max_x_choice = min(curr_cnt, k - j_prev)
for x in range(0, max_x_choice + 1):
if x ==0:
comb =1
else:
# Compute combination C(curr_cnt, x)
product = 1
for t in range(x):
product = product * (curr_cnt - t) % MOD
comb = product * inv_fact[x] % MOD
new_j = j_prev + x
new_s = (s_prev + x * r) % k
curr_dp[new_j][new_s] = (curr_dp[new_j][new_s] + prev_dp[j_prev][s_prev] * comb) % MOD
prev_dp = curr_dp
return prev_dp[k][0] % MOD
# Example usage:
# arr = [1,1,2], k=2 → Output:1
# arr = [1,2,3,4,5,6], k=3 → Output:8
# arr = [5,7,9], k=1 → Output:3
Explanation
- Modular Remainders: Each element is converted to its remainder modulo k, which simplifies the sum check to a modular sum.
- Factorials: Precompute factorials and their inverses to quickly calculate combinations (n choose x) using modular arithmetic.
- DP Table: The DP table
prev_dp[j][s]keeps track of the number of ways to choose j elements with a sum remainder of s. For each remainder, we update the DP table by considering all possible counts of elements from that remainder class. - Combination Calculation: For each remainder class, we compute the number of ways to choose x elements (up to k) and update the DP table accordingly.
This approach efficiently handles the problem constraints and provides the correct result using dynamic programming and modular arithmetic. The time complexity is O(k³), which is feasible for small values of k (up to 200). The space complexity is O(k²) due to the DP table.


(免责声明:本文为本网站出于传播商业信息之目的进行转载发布,不代表本网站的观点及立场。本文所涉文、图、音视频等资料的一切权利和法律责任归材料提供方所有和承担。本网站对此资讯文字、图片等所有信息的真实性不作任何保证或承诺,亦不构成任何购买、投资等建议,据此操作者风险自担。) 本文为转载内容,授权事宜请联系原著作权人,如有侵权,请联系本网进行删除。