问题描述
Y是住在一个名为X国的国家,这里的货币非常特殊,面值为 V 0 , V 1 , V 2 , . . . , V n V^{0}, V^{1}, V^{2},..., V^{n} V0,V1,V2,...,Vn,并且 n n n可以无限大。该国的交易规则也很特别:在一次交易中,双方只能对每种面值的货币使用不超过两次。
例如,小R想买一件价格为198的物品,货币的基数 V = 10 V = 10 V=10时,小R可以使用2张 100 ( 1 0 2 ) 100(10^{2}) 100(102)的纸币,卖家则找回2张 1 ( 1 0 0 ) 1(10^{0}) 1(100)的纸币。由于这个奇怪的规则,很多X国人都无法快速判断某个物品是否可以用这种方式交易成功,他们常常会请聪明的你来帮助。
你能帮他们判断一下,是否能按照规则用给定的货币面值 V V V来完成价格为 W W W的交易吗?
约束条件:
- V , W V, W V,W为整数,数据范围 2 ≤ V , 1 ≤ W 2 \leq V, 1 \leq W 2≤V,1≤W
代码解决
def solution(V: int, W: int) -> str:
n, m = V, W
if n <= 5:
return "YES"
while m:
remainder = m % n
if remainder <= 2:
m //= n
elif remainder >= n - 2:
m = m // n + 1
else:
return "NO"
return "YES"
if __name__ == '__main__':
print(solution(V = 10,W = 9))
print(solution(V = 200,W = 40199))
print(solution(V = 108,W = 50))
输出:
YES
YES
NO
解题思路
这道题目综合运用了数学和贪心算法知识,是一道典型的货币交易问题。
思路说明:
题目要求判断是否可以用给定的货币面值
V
V
V 来完成价格为
W
W
W 的交易,且每种面值的货币使用不超过两次。我们可以通过模拟交易过程,逐步将
W
W
W 分解为
V
V
V 的幂次项,并检查每一步是否满足使用不超过两次的限制。如果最终
W
W
W 可以被完全分解为
V
V
V 的幂次项且满足条件,则返回 “YES”,否则返回 “NO”。
解题过程:
- 初始化:将
V
V
V 和
W
W
W 分别赋值给变量
n
和m
。 - 特殊情况处理:如果 V ≤ 5 V \leq 5 V≤5,直接返回 “YES”,因为任何小于等于 5 的基数都可以通过不超过两次的使用来表示任意数。
- 模拟交易过程:
- 进入一个循环,直到 m m m 变为 0。
- 计算
m
m
m 对
n
n
n 取模的余数
remainder
。 - 如果
remainder
小于等于 2,说明当前位的货币可以使用不超过两次,直接将 m m m 除以 n n n 并继续。 - 如果
remainder
大于等于 n − 2 n - 2 n−2,说明当前位的货币可以使用一次,并将 m m m 除以 n n n 后加 1,表示进位。 - 如果
remainder
在 3 到 n − 3 n - 3 n−3 之间,说明无法满足使用不超过两次的限制,直接返回 “NO”。
- 返回结果:如果循环结束后 m m m 变为 0,说明可以完成交易,返回 “YES”。
复杂度分析:
- 时间复杂度: O ( log n W ) O(\log_n W) O(lognW),其中 W W W 是交易金额。每次循环中, m m m 至少减少 n n n 倍,因此最多需要 log n W \log_n W lognW 次循环。
- 空间复杂度: O ( 1 ) O(1) O(1),只使用了常数级别的额外空间。
知识点:
- 贪心算法:本题的核心在于每次选择最优的货币面值进行交易,这是一种典型的贪心策略。
- 模运算:通过模运算可以快速判断当前位的货币是否可以使用不超过两次。