Skip to content

Commit 2ddc7dc

Browse files
committed
1994. The Number of Good Subsets
1 parent 5bcc6e6 commit 2ddc7dc

File tree

1 file changed

+59
-0
lines changed

1 file changed

+59
-0
lines changed
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// Solution by Sergey Leschev
2+
// 1994. The Number of Good Subsets
3+
4+
function numberOfGoodSubsets(nums: number[]): number {
5+
const MOD = 1_000_000_007
6+
7+
// Primes up to 30
8+
const primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
9+
10+
// Map number to its prime factor bitmask
11+
const primeBitmask = (num: number): number => {
12+
let mask = 0
13+
for (let i = 0; i < primes.length; i++) {
14+
if (num % primes[i] === 0) {
15+
let count = 0
16+
while (num % primes[i] === 0) {
17+
count++
18+
num /= primes[i]
19+
}
20+
if (count > 1) return -1 // Number not valid for distinct prime products
21+
mask |= 1 << i
22+
}
23+
}
24+
return mask
25+
}
26+
27+
// Frequency count of numbers
28+
const freq: number[] = Array(31).fill(0)
29+
for (const num of nums) {
30+
freq[num]++
31+
}
32+
33+
// Dynamic Programming
34+
const dp: number[] = Array(1 << primes.length).fill(0)
35+
dp[0] = 1
36+
37+
for (let num = 2; num <= 30; num++) {
38+
const mask = primeBitmask(num)
39+
if (mask === -1 || freq[num] === 0) continue
40+
41+
for (let state = (1 << primes.length) - 1; state >= 0; state--) {
42+
if ((state & mask) === 0) {
43+
dp[state | mask] = (dp[state | mask] + dp[state] * freq[num]) % MOD
44+
}
45+
}
46+
}
47+
48+
// Sum all subsets except the empty one
49+
let result = dp.reduce((sum, count) => (sum + count) % MOD, 0) - 1
50+
51+
// Account for `1` if present
52+
if (freq[1] > 0) {
53+
// Use BigInt for power calculations
54+
const powerOfTwo = BigInt(2) ** BigInt(freq[1]) % BigInt(MOD)
55+
result = Number((BigInt(result) * powerOfTwo) % BigInt(MOD))
56+
}
57+
58+
return (result + MOD) % MOD // Ensure non-negative result
59+
}

0 commit comments

Comments
 (0)