返回介绍

solution / 1900-1999 / 1994.The Number of Good Subsets / README

发布于 2024-06-17 01:03:12 字数 6851 浏览 0 评论 0 收藏 0

1994. 好子集的数目

English Version

题目描述

给你一个整数数组 nums 。如果 nums 的一个子集中,所有元素的乘积可以表示为一个或多个 互不相同的质数 的乘积,那么我们称它为 好子集 。

  • 比方说,如果 nums = [1, 2, 3, 4] :
    • [2, 3] ,[1, 2, 3] 和 [1, 3] 是  子集,乘积分别为 6 = 2*3 ,6 = 2*3 和 3 = 3 。
    • [1, 4] 和 [4] 不是  子集,因为乘积分别为 4 = 2*2 和 4 = 2*2 。

请你返回 nums 中不同的  子集的数目对_ _109 + 7 取余 的结果。

nums 中的 子集 是通过删除 nums 中一些(可能一个都不删除,也可能全部都删除)元素后剩余元素组成的数组。如果两个子集删除的下标不同,那么它们被视为不同的子集。

 

示例 1:

输入:nums = [1,2,3,4]
输出:6
解释:好子集为:
- [1,2]:乘积为 2 ,可以表示为质数 2 的乘积。
- [1,2,3]:乘积为 6 ,可以表示为互不相同的质数 2 和 3 的乘积。
- [1,3]:乘积为 3 ,可以表示为质数 3 的乘积。
- [2]:乘积为 2 ,可以表示为质数 2 的乘积。
- [2,3]:乘积为 6 ,可以表示为互不相同的质数 2 和 3 的乘积。
- [3]:乘积为 3 ,可以表示为质数 3 的乘积。

示例 2:

输入:nums = [4,2,3,15]
输出:5
解释:好子集为:
- [2]:乘积为 2 ,可以表示为质数 2 的乘积。
- [2,3]:乘积为 6 ,可以表示为互不相同质数 2 和 3 的乘积。
- [2,15]:乘积为 30 ,可以表示为互不相同质数 2,3 和 5 的乘积。
- [3]:乘积为 3 ,可以表示为质数 3 的乘积。
- [15]:乘积为 15 ,可以表示为互不相同质数 3 和 5 的乘积。

 

提示:

  • 1 <= nums.length <= 105
  • 1 <= nums[i] <= 30

解法

方法一:状态压缩动态规划

注意到题目中 $nums[i]$ 的范围为 $[1, 30]$,因此我们可以预处理出所有小于等于 $30$ 的质数,即 $[2, 3, 5, 7, 11, 13, 17, 19, 23, 29]$。

好子集中,所有元素的乘积可以表示为一个或多个互不相同的质数的乘积,也即是说,每个质因数最多只能出现一次。因此,我们可以使用一个二进制数来表示一个子集中的质因数,其中二进制数的第 $i$ 位表示质数 $primes[i]$ 是否出现在子集中。

我们可以使用状态压缩动态规划的方法来求解本题。设 $f[i]$ 表示二进制数 $i$ 表示的子集中的质因数的乘积为一个或多个互不相同的质数的乘积的方案数。初始时 $f[0]=1$。

我们在 $[2,..30]$ 的范围内枚举一个数 $x$,如果 $x$ 不在 $nums$ 中,或者 $x$ 为 $4, 9, 25$ 的倍数,那么我们可以直接跳过。否则,我们可以将 $x$ 的质因数用一个二进制数 $mask$ 表示,然后我们从大到小枚举当前的状态 $state$,如果 $state$ 与 $mask$ 按位与的结果为 $mask$,那么我们可以从状态 $f[state \oplus mask]$ 转移到状态 $f[state]$,转移方程为 $f[state] = f[state] + cnt[x] \times f[state \oplus mask]$,其中 $cnt[x]$ 表示 $x$ 在 $nums$ 中出现的次数。

注意,我们没有从数字 $1$ 开始枚举,因为我们可以选择任意个数字 $1$,加入到好子集中。那么最终的答案为 $\sum_{i=1}{2^{10}-1} f[i] \times 2^{cnt[1]}$。

时间复杂度 $O(n + C \times M)$,空间复杂度 $O(M)$。其中 $n$ 为 $nums$ 的长度;而 $C$ 和 $M$ 分别为题目中 $nums[i]$ 的范围和状态的个数,本题中 $C=30$, $M=2^{10}$。

相似题目:

class Solution:
  def numberOfGoodSubsets(self, nums: List[int]) -> int:
    primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
    cnt = Counter(nums)
    mod = 10**9 + 7
    n = len(primes)
    f = [0] * (1 << n)
    f[0] = pow(2, cnt[1])
    for x in range(2, 31):
      if cnt[x] == 0 or x % 4 == 0 or x % 9 == 0 or x % 25 == 0:
        continue
      mask = 0
      for i, p in enumerate(primes):
        if x % p == 0:
          mask |= 1 << i
      for state in range((1 << n) - 1, 0, -1):
        if state & mask == mask:
          f[state] = (f[state] + cnt[x] * f[state ^ mask]) % mod
    return sum(f[i] for i in range(1, 1 << n)) % mod
class Solution {
  public int numberOfGoodSubsets(int[] nums) {
    int[] primes = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29};
    int[] cnt = new int[31];
    for (int x : nums) {
      ++cnt[x];
    }
    final int mod = (int) 1e9 + 7;
    int n = primes.length;
    long[] f = new long[1 << n];
    f[0] = 1;
    for (int i = 0; i < cnt[1]; ++i) {
      f[0] = (f[0] * 2) % mod;
    }
    for (int x = 2; x < 31; ++x) {
      if (cnt[x] == 0 || x % 4 == 0 || x % 9 == 0 || x % 25 == 0) {
        continue;
      }
      int mask = 0;
      for (int i = 0; i < n; ++i) {
        if (x % primes[i] == 0) {
          mask |= 1 << i;
        }
      }
      for (int state = (1 << n) - 1; state > 0; --state) {
        if ((state & mask) == mask) {
          f[state] = (f[state] + cnt[x] * f[state ^ mask]) % mod;
        }
      }
    }
    long ans = 0;
    for (int i = 1; i < 1 << n; ++i) {
      ans = (ans + f[i]) % mod;
    }
    return (int) ans;
  }
}
class Solution {
public:
  int numberOfGoodSubsets(vector<int>& nums) {
    int primes[10] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29};
    int cnt[31]{};
    for (int& x : nums) {
      ++cnt[x];
    }
    int n = 10;
    const int mod = 1e9 + 7;
    vector<long long> f(1 << n);
    f[0] = 1;
    for (int i = 0; i < cnt[1]; ++i) {
      f[0] = f[0] * 2 % mod;
    }
    for (int x = 2; x < 31; ++x) {
      if (cnt[x] == 0 || x % 4 == 0 || x % 9 == 0 || x % 25 == 0) {
        continue;
      }
      int mask = 0;
      for (int i = 0; i < n; ++i) {
        if (x % primes[i] == 0) {
          mask |= 1 << i;
        }
      }
      for (int state = (1 << n) - 1; state; --state) {
        if ((state & mask) == mask) {
          f[state] = (f[state] + 1LL * cnt[x] * f[state ^ mask]) % mod;
        }
      }
    }
    long long ans = 0;
    for (int i = 1; i < 1 << n; ++i) {
      ans = (ans + f[i]) % mod;
    }
    return ans;
  }
};
func numberOfGoodSubsets(nums []int) (ans int) {
  primes := []int{2, 3, 5, 7, 11, 13, 17, 19, 23, 29}
  cnt := [31]int{}
  for _, x := range nums {
    cnt[x]++
  }
  const mod int = 1e9 + 7
  n := 10
  f := make([]int, 1<<n)
  f[0] = 1
  for i := 0; i < cnt[1]; i++ {
    f[0] = f[0] * 2 % mod
  }
  for x := 2; x < 31; x++ {
    if cnt[x] == 0 || x%4 == 0 || x%9 == 0 || x%25 == 0 {
      continue
    }
    mask := 0
    for i, p := range primes {
      if x%p == 0 {
        mask |= 1 << i
      }
    }
    for state := 1<<n - 1; state > 0; state-- {
      if state&mask == mask {
        f[state] = (f[state] + f[state^mask]*cnt[x]) % mod
      }
    }
  }
  for i := 1; i < 1<<n; i++ {
    ans = (ans + f[i]) % mod
  }
  return
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文