Skip to content

Commit 57b58d5

Browse files
committed
feat: add solutions to lc problem: No.3539
1 parent 693bc69 commit 57b58d5

File tree

6 files changed

+795
-10
lines changed

6 files changed

+795
-10
lines changed

solution/3500-3599/3539.Find Sum of Array Product of Magical Sequences/README.md

Lines changed: 270 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)