LC 100267. 单面值组合的第 K 小金额
https://leetcode.cn/problems/kth-smallest-amount-with-single-denomination-combination/description/
这个应该是一个比较简单的组合问题,但是之前没有系统化地考虑过怎么做,其实大致思路就是
- k = 1, 不做任何处理
- k = 2, 选择任意两个之间的lcm, 然后因为底层重复处理了,那么就需要减去
- k = 3, 选择任意三个之间的lcm, 然后因为多减去了,那么要重新添加回来
- …
这个试过其他思路好像都不行,都会存在计算错误。但是这种方法也就是适合ways = n比较少的cases. 如果N = 15的话,那么 `ops` 的数量大约是在10k左右(我估计的),外面一层二分其实就还好。
class Solution:
def findKthSmallest(self, coins: List[int], k: int) -> int:
def gcd(a, b):
while b != 0:
a, b = b, a % b
return a
def lcm(a, b):
return (a * b) // gcd(a, b)
def precompute():
ops = []
n = len(coins)
for sz in range(1, n + 1):
import itertools
op = []
for xs in itertools.combinations(coins, sz):
l = 1
for x in xs:
l = lcm(x, l)
op.append(l)
ops.append(op)
return ops
ops = precompute()
def test(value):
res = 0
for idx, op in enumerate(ops):
sign = 1 if idx % 2 == 0 else -1
r = 0
for x in op:
r += value // x
res += r * sign
return res
coins.sort()
s, e = 0, k * coins[-1]
while s <= e:
m = (s + e) // 2
r = test(m)
# print(m, r)
if r >= k:
e = m - 1
else:
s = m + 1
return s