|
| 1 | + |
| 2 | +首先看到子集就本能想到状压,结合数据范围只有[1, 30],枚举可知道不可行的合数有 |
| 3 | +11个,于是剩下19个数来选择,并且,由于某些数之间存在公因数大于1的情况,这些数不能组合在一起, |
| 4 | +因此,可进一步剪枝,使用状压dp可以解决。 |
| 5 | + |
| 6 | +此外需要注意1的特殊性:1可选可不选,并且,乘多个1不会影响当前的数的素数性质。因此,由乘法原理可得, |
| 7 | +最终答案应乘上`2 ^ cnt[1]`的贡献 |
| 8 | + |
| 9 | +```c++ |
| 10 | +using ull = unsigned long long; |
| 11 | +ull invalid[] = {4, 8, 9, 12, 16, 18, 20, 24, 25, 27,28}; |
| 12 | +ull mod = 1e9 + 7; |
| 13 | +int cnt[31], Mutex[31]; |
| 14 | +template <class T> |
| 15 | +T qpow(T a, T n, T mod){ |
| 16 | + T ans = 1; |
| 17 | + while(n){ |
| 18 | + if(n & 1) ans = (ans * a)% mod; |
| 19 | + a = (a * a) % mod; |
| 20 | + n >>= 1; |
| 21 | + } |
| 22 | + return ans; |
| 23 | +} |
| 24 | +class Solution { |
| 25 | + int upper = 30; |
| 26 | +public: |
| 27 | + int numberOfGoodSubsets(vector<int>& a) { |
| 28 | + memset(cnt, 0, sizeof cnt); |
| 29 | + memset(Mutex, 0, sizeof Mutex); |
| 30 | + upper = 0; |
| 31 | + for(int i: a) cnt[i]++, upper = max(upper, i); |
| 32 | + for(int i: invalid) cnt[i] = 0; |
| 33 | + for(int i = 2; i <= 30; i++){ |
| 34 | + for(int j = 2; j <= 30; j++){ |
| 35 | + if(i != j && gcd(i, j) > 1) |
| 36 | + Mutex[i] |= 1 << j; |
| 37 | + } |
| 38 | + } |
| 39 | + auto ans = dfs(2, 0); |
| 40 | + if(cnt[1]) return (ans * qpow(2ull, 1ull*cnt[1], mod)) % mod; |
| 41 | + return ans; |
| 42 | + } |
| 43 | + ull dfs(int u, ull cur){ |
| 44 | + if(u > upper) return cur > 0?1: 0; |
| 45 | + auto ans = dfs(u + 1, cur) % mod; |
| 46 | + if(cnt[u] && (Mutex[u] & cur) == 0){ |
| 47 | + ans = (ans + cnt[u] * dfs(u + 1, cur | (1 << u))) % mod; |
| 48 | + } |
| 49 | + return ans % mod; |
| 50 | + } |
| 51 | +}; |
| 52 | + |
| 53 | +``` |
0 commit comments