65
65
66
66
<!-- 这里可写通用的实现逻辑 -->
67
67
68
- 状态压缩 DP。
68
+ ** 方法一:状态压缩动态规划**
69
+
70
+ 注意到题目中 $nums[ i] $ 的范围为 $[ 1, 30] $,因此我们可以预处理出所有小于等于 $30$ 的质数,即 $[ 2, 3, 5, 7, 11, 13, 17, 19, 23, 29] $。
71
+
72
+ 好子集中,所有元素的乘积可以表示为一个或多个互不相同的质数的乘积,也即是说,每个质因数最多只能出现一次。因此,我们可以使用一个二进制数来表示一个子集中的质因数,其中二进制数的第 $i$ 位表示质数 $primes[ i] $ 是否出现在子集中。
73
+
74
+ 我们可以使用状态压缩动态规划的方法来求解本题。设 $f[ i] $ 表示二进制数 $i$ 表示的子集中的质因数的乘积为一个或多个互不相同的质数的乘积的方案数。初始时 $f[ 0] =1$。
75
+
76
+ 我们在 $[ 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$ 中出现的次数。
77
+
78
+ 注意,我们没有从数字 $1$ 开始枚举,因为我们可以选择任意个数字 $1$,加入到好子集中。那么最终的答案为 $\sum_ {i=1}{2^{10}-1} f[ i] \times 2^{cnt[ 1] }$。
79
+
80
+ 时间复杂度 $O(n + C \times M)$,空间复杂度 $O(M)$。其中 $n$ 为 $nums$ 的长度;而 $C$ 和 $M$ 分别为题目中 $nums[ i] $ 的范围和状态的个数,本题中 $C=30$, $M=2^{10}$。
69
81
70
82
<!-- tabs:start -->
71
83
76
88
``` python
77
89
class Solution :
78
90
def numberOfGoodSubsets (self , nums : List[int ]) -> int :
79
- counter = Counter(nums)
91
+ primes = [2 , 3 , 5 , 7 , 11 , 13 , 17 , 19 , 23 , 29 ]
92
+ cnt = Counter(nums)
80
93
mod = 10 ** 9 + 7
81
- prime = [2 , 3 , 5 , 7 , 11 , 13 , 17 , 19 , 23 , 29 ]
82
- n = len (prime)
83
- dp = [0 ] * (1 << n)
84
- dp[0 ] = 1
94
+ n = len (primes)
95
+ f = [0 ] * (1 << n)
96
+ f[0 ] = pow (2 , cnt[1 ])
85
97
for x in range (2 , 31 ):
86
- if counter [x] == 0 or x % 4 == 0 or x % 9 == 0 or x % 25 == 0 :
98
+ if cnt [x] == 0 or x % 4 == 0 or x % 9 == 0 or x % 25 == 0 :
87
99
continue
88
100
mask = 0
89
- for i, p in enumerate (prime ):
101
+ for i, p in enumerate (primes ):
90
102
if x % p == 0 :
91
103
mask |= 1 << i
92
- for state in range (1 << n):
93
- if mask & state:
94
- continue
95
- dp[mask | state] = (dp[mask | state] + counter[x] * dp[state]) % mod
96
- ans = 0
97
- for i in range (1 , 1 << n):
98
- ans = (ans + dp[i]) % mod
99
- for i in range (counter[1 ]):
100
- ans = (ans << 1 ) % mod
101
- return ans
104
+ for state in range ((1 << n) - 1 , 0 , - 1 ):
105
+ if state & mask == mask:
106
+ f[state] = (f[state] + cnt[x] * f[state ^ mask]) % mod
107
+ return sum (f[i] for i in range (1 , 1 << n)) % mod
102
108
```
103
109
104
110
### ** Java**
@@ -107,40 +113,38 @@ class Solution:
107
113
108
114
``` java
109
115
class Solution {
110
- private static final int MOD = (int ) 1e9 + 7 ;
111
-
112
116
public int numberOfGoodSubsets (int [] nums ) {
113
- int [] counter = new int [31 ];
117
+ int [] primes = {2 , 3 , 5 , 7 , 11 , 13 , 17 , 19 , 23 , 29 };
118
+ int [] cnt = new int [31 ];
114
119
for (int x : nums) {
115
- ++ counter[x];
120
+ ++ cnt[x];
121
+ }
122
+ final int mod = (int ) 1e9 + 7 ;
123
+ int n = primes. length;
124
+ long [] f = new long [1 << n];
125
+ f[0 ] = 1 ;
126
+ for (int i = 0 ; i < cnt[1 ]; ++ i) {
127
+ f[0 ] = (f[0 ] * 2 ) % mod;
116
128
}
117
- int [] prime = {2 , 3 , 5 , 7 , 11 , 13 , 17 , 19 , 23 , 29 };
118
- int n = prime. length;
119
- long [] dp = new long [1 << n];
120
- dp[0 ] = 1 ;
121
- for (int x = 2 ; x <= 30 ; ++ x) {
122
- if (counter[x] == 0 || x % 4 == 0 || x % 9 == 0 || x % 25 == 0 ) {
129
+ for (int x = 2 ; x < 31 ; ++ x) {
130
+ if (cnt[x] == 0 || x % 4 == 0 || x % 9 == 0 || x % 25 == 0 ) {
123
131
continue ;
124
132
}
125
133
int mask = 0 ;
126
134
for (int i = 0 ; i < n; ++ i) {
127
- if (x % prime [i] == 0 ) {
128
- mask |= ( 1 << i) ;
135
+ if (x % primes [i] == 0 ) {
136
+ mask |= 1 << i;
129
137
}
130
138
}
131
- for (int state = 0 ; state < 1 << n; ++ state) {
132
- if ((mask & state) > 0 ) {
133
- continue ;
139
+ for (int state = ( 1 << n) - 1 ; state > 0 ; -- state) {
140
+ if ((state & mask) == mask ) {
141
+ f[state] = (f[state] + cnt[x] * f[state ^ mask]) % mod ;
134
142
}
135
- dp[mask | state] = (dp[mask | state] + counter[x] * dp[state]) % MOD ;
136
143
}
137
144
}
138
145
long ans = 0 ;
139
146
for (int i = 1 ; i < 1 << n; ++ i) {
140
- ans = (ans + dp[i]) % MOD ;
141
- }
142
- while (counter[1 ]-- > 0 ) {
143
- ans = (ans << 1 ) % MOD ;
147
+ ans = (ans + f[i]) % mod;
144
148
}
145
149
return (int ) ans;
146
150
}
@@ -153,71 +157,79 @@ class Solution {
153
157
class Solution {
154
158
public:
155
159
int numberOfGoodSubsets(vector<int >& nums) {
156
- vector<int > counter(31);
157
- for (int& x : nums) ++counter[ x] ;
158
- vector<int > prime = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29};
159
- const int MOD = 1e9 + 7;
160
- int n = prime.size();
161
- vector<long long > dp(1 << n);
162
- dp[ 0] = 1;
163
- for (int x = 2; x <= 30; ++x) {
164
- if (counter[ x] == 0 || x % 4 == 0 || x % 9 == 0 || x % 25 == 0) continue;
160
+ int primes[ 10] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29};
161
+ int cnt[ 31] {};
162
+ for (int& x : nums) {
163
+ ++cnt[ x] ;
164
+ }
165
+ int n = 10;
166
+ const int mod = 1e9 + 7;
167
+ vector<long long > f(1 << n);
168
+ f[ 0] = 1;
169
+ for (int i = 0; i < cnt[ 1] ; ++i) {
170
+ f[ 0] = f[ 0] * 2 % mod;
171
+ }
172
+ for (int x = 2; x < 31; ++x) {
173
+ if (cnt[ x] == 0 || x % 4 == 0 || x % 9 == 0 || x % 25 == 0) {
174
+ continue;
175
+ }
165
176
int mask = 0;
166
- for (int i = 0; i < n; ++i)
167
- if (x % prime[ i] == 0)
168
- mask |= (1 << i);
169
- for (int state = 0; state < 1 << n; ++state) {
170
- if ((mask & state) > 0) continue;
171
- dp[ mask | state] = (dp[ mask | state] + counter[ x] * dp[ state] ) % MOD;
177
+ for (int i = 0; i < n; ++i) {
178
+ if (x % primes[ i] == 0) {
179
+ mask |= 1 << i;
180
+ }
181
+ }
182
+ for (int state = (1 << n) - 1; state; --state) {
183
+ if ((state & mask) == mask) {
184
+ f[ state] = (f[ state] + 1LL * cnt[ x] * f[ state ^ mask] ) % mod;
185
+ }
172
186
}
173
187
}
174
188
long long ans = 0;
175
- for (int i = 1; i < 1 << n; ++i) ans = (ans + dp[ i] ) % MOD;
176
- while (counter[ 1] --) ans = (ans << 1) % MOD;
177
- return (int)ans;
189
+ for (int i = 1; i < 1 << n; ++i) {
190
+ ans = (ans + f[ i] ) % mod;
191
+ }
192
+ return ans;
178
193
}
179
194
};
180
195
```
181
196
182
197
### **Go**
183
198
184
199
```go
185
- func numberOfGoodSubsets(nums []int) int {
186
- counter := make([]int, 31)
200
+ func numberOfGoodSubsets(nums []int) (ans int) {
201
+ primes := []int{2, 3, 5, 7, 11, 13, 17, 19, 23, 29}
202
+ cnt := [31]int{}
187
203
for _, x := range nums {
188
- counter [x]++
204
+ cnt [x]++
189
205
}
190
206
const mod int = 1e9 + 7
191
- prime := []int{2, 3, 5, 7, 11, 13, 17, 19, 23, 29}
192
- n := len(prime)
193
- dp := make([]int, 1<<n)
194
- dp[0] = 1
195
- for x := 2; x <= 30; x++ {
196
- if counter[x] == 0 || x%4 == 0 || x%9 == 0 || x%25 == 0 {
207
+ n := 10
208
+ f := make([]int, 1<<n)
209
+ f[0] = 1
210
+ for i := 0; i < cnt[1]; i++ {
211
+ f[0] = f[0] * 2 % mod
212
+ }
213
+ for x := 2; x < 31; x++ {
214
+ if cnt[x] == 0 || x%4 == 0 || x%9 == 0 || x%25 == 0 {
197
215
continue
198
216
}
199
217
mask := 0
200
- for i, p := range prime {
218
+ for i, p := range primes {
201
219
if x%p == 0 {
202
- mask |= ( 1 << i)
220
+ mask |= 1 << i
203
221
}
204
222
}
205
- for state := 0 ; state < 1<<n ; state++ {
206
- if ( mask & state) > 0 {
207
- continue
223
+ for state := 1<<n - 1 ; state > 0 ; state-- {
224
+ if state& mask == mask {
225
+ f[state] = (f[state] + f[state^mask]*cnt[x]) % mod
208
226
}
209
- dp[mask|state] = (dp[mask|state] + counter[x]*dp[state]) % mod
210
227
}
211
228
}
212
- ans := 0
213
229
for i := 1; i < 1<<n; i++ {
214
- ans = (ans + dp[i]) % mod
215
- }
216
- for counter[1] > 0 {
217
- ans = (ans << 1) % mod
218
- counter[1]--
230
+ ans = (ans + f[i]) % mod
219
231
}
220
- return ans
232
+ return
221
233
}
222
234
```
223
235
0 commit comments