Problem Description
Given an array of positive integers (each between 1 and 30), count the number of non-empty subsets whose product is a square‐free integer. An integer is square‐free if it is not divisible by any square number other than 1. Return the answer modulo 10^9 + 7.
Key Insights
- Only numbers that are square-free (i.e. they are not divisible by any square number > 1) can contribute to a valid product. In the range 1–30, some numbers (like 4, 8, 9, etc.) are not square-free.
- The square-free condition implies that in the prime factorization of the product, no prime appears more than once.
- Use a bitmask to represent which primes have been used so far. Each allowed number (except 1) can be pre-mapped to a bitmask representing its unique prime factors.
- Since 1 is square-free and does not change the prime factors, its multiple occurrences can be handled separately using exponentiation.
- A dynamic programming approach can be employed where the state is defined by the bitmask of primes already used, and transitions are done only when adding a new element does not conflict (i.e. share any prime factor).
Space and Time Complexity
Time Complexity: O(n * 2^P) where P is the number of primes used (≈ 10), so roughly O(1000 * 1024).
Space Complexity: O(2^P) for the DP table (≈ 1024 states).
Solution
We first precompute the allowed numbers (from 1 to 30) that are square-free and build their corresponding bitmask based on their prime factors (from the set [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]). We then count the frequencies of each number in the input array. The number 1 is handled separately since its inclusion does not affect the prime factorization (but it boosts the count by a multiplicative factor of 2 for each occurrence).
We use a DP approach where dp[mask] stores the number of ways to form a subset with prime factors represented by “mask”. We initialize dp[0] = 1 (the empty subset). For each allowed number (excluding 1) present in the input (considering its frequency), we iterate over current dp states. If the current state's mask has no overlapping primes with the candidate’s mask, we update the new state (combining the masks) by adding the product of ways with the frequency of that candidate.
Finally, after processing all numbers (except 1), we multiply the valid non-empty subsets (and include the dp[0] state for scenarios only containing ones) by 2^(count1) and subtract 1 to remove the empty subset.
This approach uses a combination of counting, bitmasking, and DP to ensure valid subset formation without repeated primes.