@@ -94,32 +94,297 @@ tags:
9494
9595<!-- solution:start -->
9696
97- ### 方法一
97+ ### 方法一:组合数学 + 记忆化搜索
98+
99+ 我们设计一个函数 $\text{dfs}(i, j, k, st)$,表示当前处理到数组 $\textit{nums}$ 的第 $i$ 个元素,当前还需要从剩余的 $j$ 个位置中选择数字填入魔法序列,当前还需要满足二进制形式有 $k$ 个置位,当前上一位的进位为 $st$ 的方案数。那么答案为 $\text{dfs}(0, m, k, 0)$。
100+
101+ 函数 $\text{dfs}(i, j, k, st)$ 的执行流程如下:
102+
103+ 如果 $k < 0$ 或者 $i = n$ 且 $j > 0$,说明当前方案不可行,返回 $0$。
104+
105+ 如果 $i = n$,说明已经处理完数组 $\textit{nums}$,我们需要检查当前进位 $st$ 中是否还有置位,如果有则需要减少 $k$。如果此时 $k = 0$,说明当前方案可行,返回 $1$,否则返回 $0$。
106+
107+ 否则,我们枚举在位置 $i$ 选择 $t$ 个数字填入魔法序列($0 \leq t \leq j$),将 $t$ 个数字填入魔法序列的方案数为 $\binom{j}{t}$,数组乘积为 $\textit{nums}[ i] ^t$,更新进位为 $(t + st) >> 1$,更新需要满足的置位数为 $k - ((t + st) \& 1)$,递归调用 $\text{dfs}(i + 1, j - t, k - ((t + st) \& 1), (t + st) >> 1)$。将所有 $t$ 的方案数累加即为 $\text{dfs}(i, j, k, st)$。
108+
109+ 为了高效计算组合数 $\binom{m}{n}$,我们预处理阶乘数组 $f$ 和阶乘的逆元数组 $g$,其中 $f[ i] = i! \mod (10^9 + 7)$,$g[ i] = (i!)^{-1} \mod (10^9 + 7)$。则 $\binom{m}{n} = f[ m] \cdot g[ n] \cdot g[ m - n] \mod (10^9 + 7)$。
110+
111+ 时间复杂度 $O(n \cdot m^3 \cdot k)$,空间复杂度 $O(n \cdot m^2 \cdot k)$,其中 $n$ 是数组 $\textit{nums}$ 的长度,而 $m$ 和 $k$ 分别是题目中的参数。
98112
99113<!-- tabs:start -->
100114
101115#### Python3
102116
103117``` python
104-
118+ mx = 30
119+ mod = 10 ** 9 + 7
120+ f = [1 ] + [0 ] * mx
121+ g = [1 ] + [0 ] * mx
122+
123+ for i in range (1 , mx + 1 ):
124+ f[i] = f[i - 1 ] * i % mod
125+ g[i] = pow (f[i], mod - 2 , mod)
126+
127+
128+ def comb (m : int , n : int ) -> int :
129+ return f[m] * g[n] * g[m - n] % mod
130+
131+
132+ class Solution :
133+ def magicalSum (self , m : int , k : int , nums : List[int ]) -> int :
134+ @cache
135+ def dfs (i : int , j : int , k : int , st : int ) -> int :
136+ if k < 0 or (i == len (nums) and j > 0 ):
137+ return 0
138+ if i == len (nums):
139+ while st:
140+ k -= st & 1
141+ st >>= 1
142+ return int (k == 0 )
143+ res = 0
144+ for t in range (j + 1 ):
145+ nt = t + st
146+ p = pow (nums[i], t, mod)
147+ nk = k - (nt & 1 )
148+ res += comb(j, t) * p * dfs(i + 1 , j - t, nk, nt >> 1 )
149+ res %= mod
150+ return res
151+
152+ ans = dfs(0 , m, k, 0 )
153+ dfs.cache_clear()
154+ return ans
105155```
106156
107157#### Java
108158
109159``` java
110-
160+ class Solution {
161+ static final int N = 31 ;
162+ static final long MOD = 1_000_000_007L ;
163+ private static final long [] f = new long [N ];
164+ private static final long [] g = new long [N ];
165+ private Long [][][][] dp;
166+
167+ static {
168+ f[0 ] = 1 ;
169+ g[0 ] = 1 ;
170+ for (int i = 1 ; i < N ; ++ i) {
171+ f[i] = f[i - 1 ] * i % MOD ;
172+ g[i] = qpow(f[i], MOD - 2 );
173+ }
174+ }
175+
176+ public static long qpow (long a , long k ) {
177+ long res = 1 ;
178+ while (k != 0 ) {
179+ if ((k & 1 ) == 1 ) {
180+ res = res * a % MOD ;
181+ }
182+ a = a * a % MOD ;
183+ k >> = 1 ;
184+ }
185+ return res;
186+ }
187+
188+ public static long comb (int m , int n ) {
189+ return f[m] * g[n] % MOD * g[m - n] % MOD ;
190+ }
191+
192+ public int magicalSum (int m , int k , int [] nums ) {
193+ int n = nums. length;
194+ dp = new Long [n + 1 ][m + 1 ][k + 1 ][N ];
195+ long ans = dfs(0 , m, k, 0 , nums);
196+ return (int ) ans;
197+ }
198+
199+ private long dfs (int i , int j , int k , int st , int [] nums ) {
200+ if (k < 0 || (i == nums. length && j > 0 )) {
201+ return 0 ;
202+ }
203+ if (i == nums. length) {
204+ while (st > 0 ) {
205+ k -= (st & 1 );
206+ st >> = 1 ;
207+ }
208+ return k == 0 ? 1 : 0 ;
209+ }
210+
211+ if (dp[i][j][k][st] != null ) {
212+ return dp[i][j][k][st];
213+ }
214+
215+ long res = 0 ;
216+ for (int t = 0 ; t <= j; t++ ) {
217+ int nt = t + st;
218+ int nk = k - (nt & 1 );
219+ long p = qpow(nums[i], t);
220+ long tmp = comb(j, t) * p % MOD * dfs(i + 1 , j - t, nk, nt >> 1 , nums) % MOD ;
221+ res = (res + tmp) % MOD ;
222+ }
223+
224+ return dp[i][j][k][st] = res;
225+ }
226+ }
111227```
112228
113229#### C++
114230
115231``` cpp
116-
232+ const int N = 31 ;
233+ const long long MOD = 1'000'000'007 ;
234+
235+ long long f[N], g[N];
236+
237+ long long qpow (long long a, long long k) {
238+ long long res = 1;
239+ while (k) {
240+ if (k & 1) res = res * a % MOD;
241+ a = a * a % MOD;
242+ k >>= 1;
243+ }
244+ return res;
245+ }
246+
247+ int init = [ ] ( ) {
248+ f[ 0] = g[ 0] = 1;
249+ for (int i = 1; i < N; ++i) {
250+ f[ i] = f[ i - 1] * i % MOD;
251+ g[ i] = qpow(f[ i] , MOD - 2);
252+ }
253+ return 0;
254+ }();
255+
256+ long long comb(int m, int n) {
257+ return f[ m] * g[ n] % MOD * g[ m - n] % MOD;
258+ }
259+
260+ class Solution {
261+ vector<vector<vector<vector<long long >>>> dp;
262+
263+ long long dfs(int i, int j, int k, int st) {
264+ if (k < 0 || (i == nums.size() && j > 0)) {
265+ return 0;
266+ }
267+ if (i == nums.size()) {
268+ while (st > 0) {
269+ k -= (st & 1);
270+ st >>= 1;
271+ }
272+ return k == 0 ? 1 : 0;
273+ }
274+
275+ long long& res = dp[i][j][k][st];
276+ if (res != -1) {
277+ return res;
278+ }
279+
280+ res = 0;
281+ for (int t = 0; t <= j; ++t) {
282+ int nt = t + st;
283+ int nk = k - (nt & 1);
284+ long long p = qpow(nums[i], t);
285+ long long tmp = comb(j, t) * p % MOD * dfs(i + 1, j - t, nk, nt >> 1) % MOD;
286+ res = (res + tmp) % MOD;
287+ }
288+ return res;
289+ }
290+
291+ public:
292+ int magicalSum(int m, int k, vector<int >& nums) {
293+ int n = nums.size();
294+ this->nums = nums;
295+ dp.assign(n + 1, vector<vector<vector<long long >>>(m + 1, vector<vector<long long >>(k + 1, vector<long long >(N, -1))));
296+ return dfs(0, m, k, 0);
297+ }
298+
299+ private:
300+ vector<int > nums;
301+ };
117302```
118303
119304#### Go
120305
121306```go
122-
307+ const N = 31
308+ const MOD = 1_000_000_007
309+
310+ var f [N]int64
311+ var g [N]int64
312+
313+ func init() {
314+ f[0], g[0] = 1, 1
315+ for i := 1; i < N; i++ {
316+ f[i] = f[i-1] * int64(i) % MOD
317+ g[i] = qpow(f[i], MOD-2)
318+ }
319+ }
320+
321+ func qpow(a, k int64) int64 {
322+ res := int64(1)
323+ for k > 0 {
324+ if k&1 == 1 {
325+ res = res * a % MOD
326+ }
327+ a = a * a % MOD
328+ k >>= 1
329+ }
330+ return res
331+ }
332+
333+ func comb(m, n int) int64 {
334+ if n < 0 || n > m {
335+ return 0
336+ }
337+ return f[m] * g[n] % MOD * g[m-n] % MOD
338+ }
339+
340+ func magicalSum(m int, k int, nums []int) int {
341+ n := len(nums)
342+ dp := make([][][][]int64, n+1)
343+ for i := 0; i <= n; i++ {
344+ dp[i] = make([][][]int64, m+1)
345+ for j := 0; j <= m; j++ {
346+ dp[i][j] = make([][]int64, k+1)
347+ for l := 0; l <= k; l++ {
348+ dp[i][j][l] = make([]int64, N)
349+ for s := 0; s < N; s++ {
350+ dp[i][j][l][s] = -1
351+ }
352+ }
353+ }
354+ }
355+
356+ var dfs func(i, j, k, st int) int64
357+ dfs = func(i, j, k, st int) int64 {
358+ if k < 0 || (i == n && j > 0) {
359+ return 0
360+ }
361+ if i == n {
362+ for st > 0 {
363+ k -= st & 1
364+ st >>= 1
365+ }
366+ if k == 0 {
367+ return 1
368+ }
369+ return 0
370+ }
371+ if dp[i][j][k][st] != -1 {
372+ return dp[i][j][k][st]
373+ }
374+ res := int64(0)
375+ for t := 0; t <= j; t++ {
376+ nt := t + st
377+ nk := k - (nt & 1)
378+ p := qpow(int64(nums[i]), int64(t))
379+ tmp := comb(j, t) * p % MOD * dfs(i+1, j-t, nk, nt>>1) % MOD
380+ res = (res + tmp) % MOD
381+ }
382+ dp[i][j][k][st] = res
383+ return res
384+ }
385+
386+ return int(dfs(0, m, k, 0))
387+ }
123388```
124389
125390<!-- tabs:end -->
0 commit comments