Skip to content

Commit 547f88c

Browse files
authored
feat: add solutions to lc problem: No.3007 (doocs#3437)
No.3007.Maximum Number That Sum of the Prices Is Less Than or Equal to K
1 parent 890e7e5 commit 547f88c

File tree

4 files changed

+177
-12
lines changed

4 files changed

+177
-12
lines changed

solution/3000-3099/3007.Maximum Number That Sum of the Prices Is Less Than or Equal to K/README.md

+64-4
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,17 @@ tags:
245245

246246
<!-- solution:start -->
247247

248-
### 方法一
248+
### 方法一:二分查找 + 数位 DP
249+
250+
我们注意到,如果 $\textit{num}$ 增大,数字 $1$ 到 $\textit{num}$ 的总价值也会增大。因此,我们可以使用二分查找的方法找到最大的廉价数字。
251+
252+
我们定义二分查找的左边界 $l = 1$,由于每 $2^x + 1$ 个数中至少有一个数字是有价值的,而总价值不超过 $10^15$,因此我们可以设定二分查找的右边界 $r = 10^{18}$。
253+
254+
接下来,我们进行二分查找,对于每一个 $\textit{mid}$,我们使用数位 DP 的方法计算出 $1$ 到 $\textit{mid}$ 的总价值,如果总价值不超过 $k$,则说明 $\textit{mid}$ 是一个廉价数字,我们将左边界 $l$ 更新为 $\textit{mid}$,否则我们将右边界 $r$ 更新为 $\textit{mid} - 1$。
255+
256+
最后,我们返回左边界 $l$ 即可。
257+
258+
时间复杂度 $O(\log^2 k)$,空间复杂度 $O(\log k)$。
249259

250260
<!-- tabs:start -->
251261

@@ -332,7 +342,7 @@ public:
332342
ll l = 1, r = 1e17;
333343
ll num = 0;
334344
ll f[65][65];
335-
function<ll(int, int, bool)> dfs = [&](int pos, int cnt, bool limit) -> ll {
345+
auto dfs = [&](auto&& dfs, int pos, int cnt, bool limit) -> ll {
336346
if (pos == 0) {
337347
return cnt;
338348
}
@@ -342,7 +352,7 @@ public:
342352
int up = limit ? num >> (pos - 1) & 1 : 1;
343353
ll ans = 0;
344354
for (int i = 0; i <= up; ++i) {
345-
ans += dfs(pos - 1, cnt + (i == 1 && pos % x == 0), limit && i == up);
355+
ans += dfs(dfs, pos - 1, cnt + (i == 1 && pos % x == 0), limit && i == up);
346356
}
347357
if (!limit) {
348358
f[pos][cnt] = ans;
@@ -354,7 +364,7 @@ public:
354364
num = mid;
355365
memset(f, -1, sizeof(f));
356366
int pos = 64 - __builtin_clzll(mid);
357-
if (dfs(pos, 0, true) <= k) {
367+
if (dfs(dfs, pos, 0, true) <= k) {
358368
l = mid;
359369
} else {
360370
r = mid - 1;
@@ -416,6 +426,56 @@ func findMaximumNumber(k int64, x int) int64 {
416426
}
417427
```
418428

429+
#### TypeScript
430+
431+
```ts
432+
function findMaximumNumber(k: number, x: number): number {
433+
let [l, r] = [1n, 10n ** 17n];
434+
let num: bigint;
435+
const f: bigint[][] = Array.from({ length: 65 }, () => Array(65).fill(-1n));
436+
437+
const dfs = (pos: number, cnt: number, limit: boolean): bigint => {
438+
if (pos === 0) {
439+
return BigInt(cnt);
440+
}
441+
if (!limit && f[pos][cnt] !== -1n) {
442+
return f[pos][cnt];
443+
}
444+
let ans: bigint = 0n;
445+
let up: number = 1;
446+
if (limit) {
447+
up = Number((num >> BigInt(pos - 1)) & 1n);
448+
}
449+
for (let i = 0; i <= up; i++) {
450+
let v: number = cnt;
451+
if (i === 1 && pos % x === 0) {
452+
v++;
453+
}
454+
ans += dfs(pos - 1, v, limit && i === up);
455+
}
456+
if (!limit) {
457+
f[pos][cnt] = ans;
458+
}
459+
return ans;
460+
};
461+
462+
while (l < r) {
463+
let mid: bigint = (l + r + 1n) >> 1n;
464+
num = mid;
465+
let m: number = num.toString(2).length;
466+
for (let i = 0; i < f.length; i++) {
467+
f[i].fill(-1n);
468+
}
469+
if (dfs(m, 0, true) <= BigInt(k)) {
470+
l = mid;
471+
} else {
472+
r = mid - 1n;
473+
}
474+
}
475+
return Number(l);
476+
}
477+
```
478+
419479
<!-- tabs:end -->
420480

421481
<!-- solution:end -->

solution/3000-3099/3007.Maximum Number That Sum of the Prices Is Less Than or Equal to K/README_EN.md

+64-4
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,17 @@ tags:
249249

250250
<!-- solution:start -->
251251

252-
### Solution 1
252+
### Solution 1: Binary Search + Digit DP
253+
254+
We notice that if $\textit{num}$ increases, the total value from $1$ to $\textit{num}$ also increases. Therefore, we can use a binary search method to find the largest cheap number.
255+
256+
We define the left boundary of the binary search as $l = 1$. Since there is at least one valuable number in every $2^x + 1$ numbers, and the total value does not exceed $10^{15}$, we can set the right boundary of the binary search as $r = 10^{18}$.
257+
258+
Next, we perform a binary search. For each $\textit{mid}$, we use the digit DP method to calculate the total value from $1$ to $\textit{mid}$. If the total value does not exceed $k$, it means $\textit{mid}$ is a cheap number, and we update the left boundary $l$ to $\textit{mid}$. Otherwise, we update the right boundary $r$ to $\textit{mid} - 1$.
259+
260+
Finally, we return the left boundary $l$.
261+
262+
The time complexity is $O(\log^2 k)$, and the space complexity is $O(\log k)$.
253263

254264
<!-- tabs:start -->
255265

@@ -336,7 +346,7 @@ public:
336346
ll l = 1, r = 1e17;
337347
ll num = 0;
338348
ll f[65][65];
339-
function<ll(int, int, bool)> dfs = [&](int pos, int cnt, bool limit) -> ll {
349+
auto dfs = [&](auto&& dfs, int pos, int cnt, bool limit) -> ll {
340350
if (pos == 0) {
341351
return cnt;
342352
}
@@ -346,7 +356,7 @@ public:
346356
int up = limit ? num >> (pos - 1) & 1 : 1;
347357
ll ans = 0;
348358
for (int i = 0; i <= up; ++i) {
349-
ans += dfs(pos - 1, cnt + (i == 1 && pos % x == 0), limit && i == up);
359+
ans += dfs(dfs, pos - 1, cnt + (i == 1 && pos % x == 0), limit && i == up);
350360
}
351361
if (!limit) {
352362
f[pos][cnt] = ans;
@@ -358,7 +368,7 @@ public:
358368
num = mid;
359369
memset(f, -1, sizeof(f));
360370
int pos = 64 - __builtin_clzll(mid);
361-
if (dfs(pos, 0, true) <= k) {
371+
if (dfs(dfs, pos, 0, true) <= k) {
362372
l = mid;
363373
} else {
364374
r = mid - 1;
@@ -420,6 +430,56 @@ func findMaximumNumber(k int64, x int) int64 {
420430
}
421431
```
422432

433+
#### TypeScript
434+
435+
```ts
436+
function findMaximumNumber(k: number, x: number): number {
437+
let [l, r] = [1n, 10n ** 17n];
438+
let num: bigint;
439+
const f: bigint[][] = Array.from({ length: 65 }, () => Array(65).fill(-1n));
440+
441+
const dfs = (pos: number, cnt: number, limit: boolean): bigint => {
442+
if (pos === 0) {
443+
return BigInt(cnt);
444+
}
445+
if (!limit && f[pos][cnt] !== -1n) {
446+
return f[pos][cnt];
447+
}
448+
let ans: bigint = 0n;
449+
let up: number = 1;
450+
if (limit) {
451+
up = Number((num >> BigInt(pos - 1)) & 1n);
452+
}
453+
for (let i = 0; i <= up; i++) {
454+
let v: number = cnt;
455+
if (i === 1 && pos % x === 0) {
456+
v++;
457+
}
458+
ans += dfs(pos - 1, v, limit && i === up);
459+
}
460+
if (!limit) {
461+
f[pos][cnt] = ans;
462+
}
463+
return ans;
464+
};
465+
466+
while (l < r) {
467+
let mid: bigint = (l + r + 1n) >> 1n;
468+
num = mid;
469+
let m: number = num.toString(2).length;
470+
for (let i = 0; i < f.length; i++) {
471+
f[i].fill(-1n);
472+
}
473+
if (dfs(m, 0, true) <= BigInt(k)) {
474+
l = mid;
475+
} else {
476+
r = mid - 1n;
477+
}
478+
}
479+
return Number(l);
480+
}
481+
```
482+
423483
<!-- tabs:end -->
424484

425485
<!-- solution:end -->

solution/3000-3099/3007.Maximum Number That Sum of the Prices Is Less Than or Equal to K/Solution.cpp

+4-4
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ class Solution {
55
ll l = 1, r = 1e17;
66
ll num = 0;
77
ll f[65][65];
8-
function<ll(int, int, bool)> dfs = [&](int pos, int cnt, bool limit) -> ll {
8+
auto dfs = [&](auto&& dfs, int pos, int cnt, bool limit) -> ll {
99
if (pos == 0) {
1010
return cnt;
1111
}
@@ -15,7 +15,7 @@ class Solution {
1515
int up = limit ? num >> (pos - 1) & 1 : 1;
1616
ll ans = 0;
1717
for (int i = 0; i <= up; ++i) {
18-
ans += dfs(pos - 1, cnt + (i == 1 && pos % x == 0), limit && i == up);
18+
ans += dfs(dfs, pos - 1, cnt + (i == 1 && pos % x == 0), limit && i == up);
1919
}
2020
if (!limit) {
2121
f[pos][cnt] = ans;
@@ -27,12 +27,12 @@ class Solution {
2727
num = mid;
2828
memset(f, -1, sizeof(f));
2929
int pos = 64 - __builtin_clzll(mid);
30-
if (dfs(pos, 0, true) <= k) {
30+
if (dfs(dfs, pos, 0, true) <= k) {
3131
l = mid;
3232
} else {
3333
r = mid - 1;
3434
}
3535
}
3636
return l;
3737
}
38-
};
38+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
function findMaximumNumber(k: number, x: number): number {
2+
let [l, r] = [1n, 10n ** 17n];
3+
let num: bigint;
4+
const f: bigint[][] = Array.from({ length: 65 }, () => Array(65).fill(-1n));
5+
6+
const dfs = (pos: number, cnt: number, limit: boolean): bigint => {
7+
if (pos === 0) {
8+
return BigInt(cnt);
9+
}
10+
if (!limit && f[pos][cnt] !== -1n) {
11+
return f[pos][cnt];
12+
}
13+
let ans: bigint = 0n;
14+
let up: number = 1;
15+
if (limit) {
16+
up = Number((num >> BigInt(pos - 1)) & 1n);
17+
}
18+
for (let i = 0; i <= up; i++) {
19+
let v: number = cnt;
20+
if (i === 1 && pos % x === 0) {
21+
v++;
22+
}
23+
ans += dfs(pos - 1, v, limit && i === up);
24+
}
25+
if (!limit) {
26+
f[pos][cnt] = ans;
27+
}
28+
return ans;
29+
};
30+
31+
while (l < r) {
32+
let mid: bigint = (l + r + 1n) >> 1n;
33+
num = mid;
34+
let m: number = num.toString(2).length;
35+
for (let i = 0; i < f.length; i++) {
36+
f[i].fill(-1n);
37+
}
38+
if (dfs(m, 0, true) <= BigInt(k)) {
39+
l = mid;
40+
} else {
41+
r = mid - 1n;
42+
}
43+
}
44+
return Number(l);
45+
}

0 commit comments

Comments
 (0)