原题地址878. 第 N 个神奇数字
如果正整数可以被 A 或 B 整除,那么它是神奇的。
返回第 N 个神奇数字。由于答案可能非常大,返回它模 10^9 + 7
的结果。
示例 1:
输入:N = 1, A = 2, B = 3
输出:2
示例 2:
输入:N = 4, A = 2, B = 3
输出:6
示例 3:
输入:N = 5, A = 2, B = 4
输出:10
示例 4:
输入:N = 3, A = 6, B = 4
输出:8
提示:
1 <= N <= 10^9
2 <= A <= 40000
2 <= B <= 4000
算法
首先找出最大公约数C,如果C为A或B其中一个数,直接输出C*N;否则计算出最小公倍数D。
在一个最小公倍数的周期内即(i*D,(i+1)*D],只有(i+1)*D可以同时整除A和B,其余的数最多仅能整除A或B其中一个。
每一个周期内,神奇的数的总数为D/A+D/B-1
因此把N除以D/A+D/B-1的余数n单独拿出来计算即可。
保证A<B之后,在一个公倍数周期内,A、B可以整除的神奇数分别有a=D/A、b=D/B,且a>b。
然后根据b每增加1,对应的a增加多少可以简化运算,使得结果更快得到第n个数
代码
class Solution:
def nthMagicalNumber(self, N, A, B):
"""
:type N: int
:type A: int
:type B: int
:rtype: int
"""
def gcb(p, q):
if p == q:
return p
if p < q:
return gcb(q, p)
else:
if p & 1:
if q & 1:
return gcb(p - q, q)
else:
return gcb(p, q >> 1)
else:
if q & 1:
return gcb(p >> 1, q)
else:
return gcb(p >> 1, q >> 1) << 1
C = gcb(A, B)
if C == A or C == B:
return C * N % 1000000007
if A > B:
A, B = B, A
D = A * (B // C)
a, b = D // A, D // B
m, n = N // (a + b - 1), N % (a + b - 1)
y = int(n / (a / b + 1))
x = int(a / b * y)
nowA, nowB = A * x, B * y
while x + y < n:
if nowA + A < nowB + B:
nowA += A
x += 1
else:
nowB += B
y += 1
return (max(nowA, nowB) + m * D) % 1000000007