Count the Number of Square-Free Subsets

medium dp bitmask

Problem

Given an array nums of positive integers (each 1..30), count the non-empty subsets whose product is square-free (no prime appears with exponent ≥ 2). Return the count modulo 10^9 + 7.

Inputnums = [3,4,4,5]
Output3
4 is not square-free, so it is unusable. The square-free non-empty subsets are {3}, {5}, {3,5}.

def square_free_subsets(nums):
    MOD = 10**9 + 7
    primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]

    def mask_of(x):
        m = 0
        for b, p in enumerate(primes):
            if x % p == 0:
                if x % (p * p) == 0:
                    return -1            # not square-free
                m |= 1 << b
        return m

    dp = [0] * (1 << len(primes))
    dp[0] = 1                            # empty subset
    for x in nums:
        m = mask_of(x)
        if m == -1:
            continue
        for s in range((1 << len(primes)) - 1, -1, -1):
            if (s & m) == 0:             # disjoint primes -> can add x
                dp[s | m] = (dp[s | m] + dp[s]) % MOD
    return (sum(dp) - 1) % MOD           # subtract the empty subset
function squareFreeSubsets(nums) {
  const MOD = 1000000007n;
  const primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29];
  const maskOf = (x) => {
    let m = 0;
    for (let b = 0; b < primes.length; b++) {
      const p = primes[b];
      if (x % p === 0) {
        if (x % (p * p) === 0) return -1;
        m |= 1 << b;
      }
    }
    return m;
  };
  const dp = new Array(1 << primes.length).fill(0n);
  dp[0] = 1n;
  for (const x of nums) {
    const m = maskOf(x);
    if (m === -1) continue;
    for (let s = dp.length - 1; s >= 0; s--) {
      if ((s & m) === 0) dp[s | m] = (dp[s | m] + dp[s]) % MOD;
    }
  }
  let total = 0n;
  for (const v of dp) total = (total + v) % MOD;
  return Number((total - 1n + MOD) % MOD);
}
class Solution {
    public int squareFreeSubsets(int[] nums) {
        long MOD = 1_000_000_007L;
        int[] primes = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29};
        long[] dp = new long[1 << primes.length];
        dp[0] = 1;
        for (int x : nums) {
            int m = 0;
            boolean ok = true;
            for (int b = 0; b < primes.length; b++) {
                int p = primes[b];
                if (x % p == 0) {
                    if (x % (p * p) == 0) { ok = false; break; }
                    m |= 1 << b;
                }
            }
            if (!ok) continue;
            for (int s = dp.length - 1; s >= 0; s--) {
                if ((s & m) == 0) dp[s | m] = (dp[s | m] + dp[s]) % MOD;
            }
        }
        long total = 0;
        for (long v : dp) total = (total + v) % MOD;
        return (int) ((total - 1 + MOD) % MOD);
    }
}
int squareFreeSubsets(vector<int>& nums) {
    const long long MOD = 1000000007LL;
    int primes[] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29};
    int P = 10;
    vector<long long> dp(1 << P, 0);
    dp[0] = 1;
    for (int x : nums) {
        int m = 0; bool ok = true;
        for (int b = 0; b < P; b++) {
            int p = primes[b];
            if (x % p == 0) {
                if (x % (p * p) == 0) { ok = false; break; }
                m |= 1 << b;
            }
        }
        if (!ok) continue;
        for (int s = (1 << P) - 1; s >= 0; s--) {
            if ((s & m) == 0) dp[s | m] = (dp[s | m] + dp[s]) % MOD;
        }
    }
    long long total = 0;
    for (long long v : dp) total = (total + v) % MOD;
    return (int) ((total - 1 + MOD) % MOD);
}
Time: O(n · 2^10) Space: O(2^10)