mirror of https://github.com/doocs/leetcode.git
feat: add solutions to lc problem: No.3007 (#3437)
No.3007.Maximum Number That Sum of the Prices Is Less Than or Equal to K
This commit is contained in:
parent
890e7e5afa
commit
547f88c0e2
|
|
@ -245,7 +245,17 @@ tags:
|
|||
|
||||
<!-- solution:start -->
|
||||
|
||||
### 方法一
|
||||
### 方法一:二分查找 + 数位 DP
|
||||
|
||||
我们注意到,如果 $\textit{num}$ 增大,数字 $1$ 到 $\textit{num}$ 的总价值也会增大。因此,我们可以使用二分查找的方法找到最大的廉价数字。
|
||||
|
||||
我们定义二分查找的左边界 $l = 1$,由于每 $2^x + 1$ 个数中至少有一个数字是有价值的,而总价值不超过 $10^15$,因此我们可以设定二分查找的右边界 $r = 10^{18}$。
|
||||
|
||||
接下来,我们进行二分查找,对于每一个 $\textit{mid}$,我们使用数位 DP 的方法计算出 $1$ 到 $\textit{mid}$ 的总价值,如果总价值不超过 $k$,则说明 $\textit{mid}$ 是一个廉价数字,我们将左边界 $l$ 更新为 $\textit{mid}$,否则我们将右边界 $r$ 更新为 $\textit{mid} - 1$。
|
||||
|
||||
最后,我们返回左边界 $l$ 即可。
|
||||
|
||||
时间复杂度 $O(\log^2 k)$,空间复杂度 $O(\log k)$。
|
||||
|
||||
<!-- tabs:start -->
|
||||
|
||||
|
|
@ -332,7 +342,7 @@ public:
|
|||
ll l = 1, r = 1e17;
|
||||
ll num = 0;
|
||||
ll f[65][65];
|
||||
function<ll(int, int, bool)> dfs = [&](int pos, int cnt, bool limit) -> ll {
|
||||
auto dfs = [&](auto&& dfs, int pos, int cnt, bool limit) -> ll {
|
||||
if (pos == 0) {
|
||||
return cnt;
|
||||
}
|
||||
|
|
@ -342,7 +352,7 @@ public:
|
|||
int up = limit ? num >> (pos - 1) & 1 : 1;
|
||||
ll ans = 0;
|
||||
for (int i = 0; i <= up; ++i) {
|
||||
ans += dfs(pos - 1, cnt + (i == 1 && pos % x == 0), limit && i == up);
|
||||
ans += dfs(dfs, pos - 1, cnt + (i == 1 && pos % x == 0), limit && i == up);
|
||||
}
|
||||
if (!limit) {
|
||||
f[pos][cnt] = ans;
|
||||
|
|
@ -354,7 +364,7 @@ public:
|
|||
num = mid;
|
||||
memset(f, -1, sizeof(f));
|
||||
int pos = 64 - __builtin_clzll(mid);
|
||||
if (dfs(pos, 0, true) <= k) {
|
||||
if (dfs(dfs, pos, 0, true) <= k) {
|
||||
l = mid;
|
||||
} else {
|
||||
r = mid - 1;
|
||||
|
|
@ -416,6 +426,56 @@ func findMaximumNumber(k int64, x int) int64 {
|
|||
}
|
||||
```
|
||||
|
||||
#### TypeScript
|
||||
|
||||
```ts
|
||||
function findMaximumNumber(k: number, x: number): number {
|
||||
let [l, r] = [1n, 10n ** 17n];
|
||||
let num: bigint;
|
||||
const f: bigint[][] = Array.from({ length: 65 }, () => Array(65).fill(-1n));
|
||||
|
||||
const dfs = (pos: number, cnt: number, limit: boolean): bigint => {
|
||||
if (pos === 0) {
|
||||
return BigInt(cnt);
|
||||
}
|
||||
if (!limit && f[pos][cnt] !== -1n) {
|
||||
return f[pos][cnt];
|
||||
}
|
||||
let ans: bigint = 0n;
|
||||
let up: number = 1;
|
||||
if (limit) {
|
||||
up = Number((num >> BigInt(pos - 1)) & 1n);
|
||||
}
|
||||
for (let i = 0; i <= up; i++) {
|
||||
let v: number = cnt;
|
||||
if (i === 1 && pos % x === 0) {
|
||||
v++;
|
||||
}
|
||||
ans += dfs(pos - 1, v, limit && i === up);
|
||||
}
|
||||
if (!limit) {
|
||||
f[pos][cnt] = ans;
|
||||
}
|
||||
return ans;
|
||||
};
|
||||
|
||||
while (l < r) {
|
||||
let mid: bigint = (l + r + 1n) >> 1n;
|
||||
num = mid;
|
||||
let m: number = num.toString(2).length;
|
||||
for (let i = 0; i < f.length; i++) {
|
||||
f[i].fill(-1n);
|
||||
}
|
||||
if (dfs(m, 0, true) <= BigInt(k)) {
|
||||
l = mid;
|
||||
} else {
|
||||
r = mid - 1n;
|
||||
}
|
||||
}
|
||||
return Number(l);
|
||||
}
|
||||
```
|
||||
|
||||
<!-- tabs:end -->
|
||||
|
||||
<!-- solution:end -->
|
||||
|
|
|
|||
|
|
@ -249,7 +249,17 @@ tags:
|
|||
|
||||
<!-- solution:start -->
|
||||
|
||||
### Solution 1
|
||||
### Solution 1: Binary Search + Digit DP
|
||||
|
||||
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.
|
||||
|
||||
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}$.
|
||||
|
||||
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$.
|
||||
|
||||
Finally, we return the left boundary $l$.
|
||||
|
||||
The time complexity is $O(\log^2 k)$, and the space complexity is $O(\log k)$.
|
||||
|
||||
<!-- tabs:start -->
|
||||
|
||||
|
|
@ -336,7 +346,7 @@ public:
|
|||
ll l = 1, r = 1e17;
|
||||
ll num = 0;
|
||||
ll f[65][65];
|
||||
function<ll(int, int, bool)> dfs = [&](int pos, int cnt, bool limit) -> ll {
|
||||
auto dfs = [&](auto&& dfs, int pos, int cnt, bool limit) -> ll {
|
||||
if (pos == 0) {
|
||||
return cnt;
|
||||
}
|
||||
|
|
@ -346,7 +356,7 @@ public:
|
|||
int up = limit ? num >> (pos - 1) & 1 : 1;
|
||||
ll ans = 0;
|
||||
for (int i = 0; i <= up; ++i) {
|
||||
ans += dfs(pos - 1, cnt + (i == 1 && pos % x == 0), limit && i == up);
|
||||
ans += dfs(dfs, pos - 1, cnt + (i == 1 && pos % x == 0), limit && i == up);
|
||||
}
|
||||
if (!limit) {
|
||||
f[pos][cnt] = ans;
|
||||
|
|
@ -358,7 +368,7 @@ public:
|
|||
num = mid;
|
||||
memset(f, -1, sizeof(f));
|
||||
int pos = 64 - __builtin_clzll(mid);
|
||||
if (dfs(pos, 0, true) <= k) {
|
||||
if (dfs(dfs, pos, 0, true) <= k) {
|
||||
l = mid;
|
||||
} else {
|
||||
r = mid - 1;
|
||||
|
|
@ -420,6 +430,56 @@ func findMaximumNumber(k int64, x int) int64 {
|
|||
}
|
||||
```
|
||||
|
||||
#### TypeScript
|
||||
|
||||
```ts
|
||||
function findMaximumNumber(k: number, x: number): number {
|
||||
let [l, r] = [1n, 10n ** 17n];
|
||||
let num: bigint;
|
||||
const f: bigint[][] = Array.from({ length: 65 }, () => Array(65).fill(-1n));
|
||||
|
||||
const dfs = (pos: number, cnt: number, limit: boolean): bigint => {
|
||||
if (pos === 0) {
|
||||
return BigInt(cnt);
|
||||
}
|
||||
if (!limit && f[pos][cnt] !== -1n) {
|
||||
return f[pos][cnt];
|
||||
}
|
||||
let ans: bigint = 0n;
|
||||
let up: number = 1;
|
||||
if (limit) {
|
||||
up = Number((num >> BigInt(pos - 1)) & 1n);
|
||||
}
|
||||
for (let i = 0; i <= up; i++) {
|
||||
let v: number = cnt;
|
||||
if (i === 1 && pos % x === 0) {
|
||||
v++;
|
||||
}
|
||||
ans += dfs(pos - 1, v, limit && i === up);
|
||||
}
|
||||
if (!limit) {
|
||||
f[pos][cnt] = ans;
|
||||
}
|
||||
return ans;
|
||||
};
|
||||
|
||||
while (l < r) {
|
||||
let mid: bigint = (l + r + 1n) >> 1n;
|
||||
num = mid;
|
||||
let m: number = num.toString(2).length;
|
||||
for (let i = 0; i < f.length; i++) {
|
||||
f[i].fill(-1n);
|
||||
}
|
||||
if (dfs(m, 0, true) <= BigInt(k)) {
|
||||
l = mid;
|
||||
} else {
|
||||
r = mid - 1n;
|
||||
}
|
||||
}
|
||||
return Number(l);
|
||||
}
|
||||
```
|
||||
|
||||
<!-- tabs:end -->
|
||||
|
||||
<!-- solution:end -->
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ public:
|
|||
ll l = 1, r = 1e17;
|
||||
ll num = 0;
|
||||
ll f[65][65];
|
||||
function<ll(int, int, bool)> dfs = [&](int pos, int cnt, bool limit) -> ll {
|
||||
auto dfs = [&](auto&& dfs, int pos, int cnt, bool limit) -> ll {
|
||||
if (pos == 0) {
|
||||
return cnt;
|
||||
}
|
||||
|
|
@ -15,7 +15,7 @@ public:
|
|||
int up = limit ? num >> (pos - 1) & 1 : 1;
|
||||
ll ans = 0;
|
||||
for (int i = 0; i <= up; ++i) {
|
||||
ans += dfs(pos - 1, cnt + (i == 1 && pos % x == 0), limit && i == up);
|
||||
ans += dfs(dfs, pos - 1, cnt + (i == 1 && pos % x == 0), limit && i == up);
|
||||
}
|
||||
if (!limit) {
|
||||
f[pos][cnt] = ans;
|
||||
|
|
@ -27,7 +27,7 @@ public:
|
|||
num = mid;
|
||||
memset(f, -1, sizeof(f));
|
||||
int pos = 64 - __builtin_clzll(mid);
|
||||
if (dfs(pos, 0, true) <= k) {
|
||||
if (dfs(dfs, pos, 0, true) <= k) {
|
||||
l = mid;
|
||||
} else {
|
||||
r = mid - 1;
|
||||
|
|
@ -35,4 +35,4 @@ public:
|
|||
}
|
||||
return l;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,45 @@
|
|||
function findMaximumNumber(k: number, x: number): number {
|
||||
let [l, r] = [1n, 10n ** 17n];
|
||||
let num: bigint;
|
||||
const f: bigint[][] = Array.from({ length: 65 }, () => Array(65).fill(-1n));
|
||||
|
||||
const dfs = (pos: number, cnt: number, limit: boolean): bigint => {
|
||||
if (pos === 0) {
|
||||
return BigInt(cnt);
|
||||
}
|
||||
if (!limit && f[pos][cnt] !== -1n) {
|
||||
return f[pos][cnt];
|
||||
}
|
||||
let ans: bigint = 0n;
|
||||
let up: number = 1;
|
||||
if (limit) {
|
||||
up = Number((num >> BigInt(pos - 1)) & 1n);
|
||||
}
|
||||
for (let i = 0; i <= up; i++) {
|
||||
let v: number = cnt;
|
||||
if (i === 1 && pos % x === 0) {
|
||||
v++;
|
||||
}
|
||||
ans += dfs(pos - 1, v, limit && i === up);
|
||||
}
|
||||
if (!limit) {
|
||||
f[pos][cnt] = ans;
|
||||
}
|
||||
return ans;
|
||||
};
|
||||
|
||||
while (l < r) {
|
||||
let mid: bigint = (l + r + 1n) >> 1n;
|
||||
num = mid;
|
||||
let m: number = num.toString(2).length;
|
||||
for (let i = 0; i < f.length; i++) {
|
||||
f[i].fill(-1n);
|
||||
}
|
||||
if (dfs(m, 0, true) <= BigInt(k)) {
|
||||
l = mid;
|
||||
} else {
|
||||
r = mid - 1n;
|
||||
}
|
||||
}
|
||||
return Number(l);
|
||||
}
|
||||
Loading…
Reference in New Issue