📌  相关文章
📜  LCM和GCD之和等于N的所有可能对的计数(1)

📅  最后修改于: 2023-12-03 15:17:18.047000             🧑  作者: Mango

题目介绍

给定一个正整数N,求有多少个正整数对(a,b),满足它们的最小公倍数(LCM)和最大公约数(GCD)的和等于N。

解法思路

对于一个正整数对(a,b),设它们的最大公约数是d,则它们的最小公倍数是ab/d,且满足ab/d*N。因此,对于一个固定的d,我们需要求出有多少个(a,b)满足上述条件。我们称a,b互质,当且仅当它们的最大公约数d=1。

假设N的质因数分解式为N=p1^e1p2^e2...pk^ek,根据唯一分解定理,我们知道p1,p2,...,pk是N的所有质因子,e1,e2,...,ek是它们的指数。我们枚举d为N的因子,即d的质因数分解式为d=q1^f1q2^f2*...*qm^fm,其中q1,q2,...,qm是N的质因子的子集,f1,f2,...,fm是它们的指数。

首先,在d的约束下,我们需要找到有多少个互质的(a,b),这个问题很容易解决。不妨设a和b的质因数分解式分别为a=p1^x1p2^x2...pk^xk,b=p1^y1p2^y2*...*pk^yk,那么它们互质当且仅当xi和yi都为0或1。因为此时它们的最大公约数是1。

设有st个互质的正整数对(a,b),使它们的最大公约数为d。

接下来,我们要找到在d的约束下,有多少个正整数对(a,b),使它们的最小公倍数为N/d。不妨设a和b的最小公倍数是N/d,即a=b/d,那么它们的质因数分解式应满足如下两个条件:

  • 1.对于所有的i∈[1,k],xi≤ei-fj,其中j∈[1,m],qj=pi。
  • 2.存在一个j∈[1,m],使fj≤ei-xj,且qi=pi。

这两个条件的含义是,除了qm之外的其它质因子所取的指数,都不能超过N的质因子分解后相应质因子的指数减去d所取的相应质因子的指数。同时,qm此时的指数应该小于等于xk。

设有Sd个符合要求的正整数对(a,b),使它们的最小公倍数为N/d。

那么,我们只需要枚举N的因数d,计算出Sd,然后根据容斥定理求出所有符合条件的(a,b)对数。即

ans = Σst * ΣSd * (-1)^{d/N}。

代码实现
def factorize(N):
    """
    分解N的质因数,返回每个质因数的指数。
    """
    factors = {}
    i = 2
    while i*i <= N:
        while N % i == 0:
            N //= i
            factors[i] = factors.get(i,0) + 1
        i += 1
    if N > 1:
        factors[N] = 1
    return factors

def count_primes(N):
    """
    计算N以内的质数数量。
    """
    if N <= 1:
        return 0
    cnt = [1] * (N+1)
    cnt[0] = cnt[1] = 0
    i = 2
    while i*i <= N:
        if cnt[i]:
            j = i*i
            while j <= N:
                cnt[j] = 0
                j += i
        i += 1
    return sum(cnt)

def solve(N):
    """
    求有多少个正整数对(a,b),满足它们的最小公倍数和最大公约数的和等于N。
    """
    factors = factorize(N)
    m = len(factors)
    p = list(factors.keys())
    ans = 0
    for mask in range(1<<m):
        d = 1
        for i in range(m):
            if mask & (1<<i):
                d *= p[i]
        st = (1<<sum(factors.values())) - count_primes(d-1) - 1
        Sd = 1
        for i in range(m):
            if mask & (1<<i):
                ei = factors[p[i]]
                fj = 0
                for j in range(m):
                    if j != i and mask & (1<<j) and p[j] == p[i]:
                        fj = factors[p[j]]
                        break
                Sd *= (ei - fj + 1)
        ans += ((-1)**(N//d)) * st * Sd
    return ans
总结

本题解详细介绍了求解LCM和GCD之和等于N的所有可能对的计数的思路和实现方式,希望对你有所帮助。