📌  相关文章
📜  [L, R] 范围内的数字计数,可以表示为两个完美幂的和(1)

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

用两个完美幂的和表示区间内的数字计数

给定一个区间 [L, R],需要求出在该区间内可以用两个完美幂的和表示的数字的个数。

完美幂是指形如 $a^b$ 的整数,其中 $a$ 为正整数且 $b > 1$ 为正整数。

例如,$1, 2, 4, 8, 16, \ldots$ 都是完美幂。

思路

我们可以枚举两个完美幂的和 $a^b + c^d$,其中 $a$、$b$、$c$、$d$ 都是正整数。如果这个和在区间 [L, R] 中,那么我们就可以增加计数器的值。

那么如何枚举呢?由于区间 [L, R] 最大只有 $10^{18}$,为了避免不必要的计算,我们可以把完美幂的底数 $a$ 和 $c$ 的范围限定在 $10^6$ 以内。

当 $a$ 和 $c$ 确定后,我们可以通过二分或者牛顿迭代等方式求出满足 $a^b + c^d$ 在区间 [L, R] 中的最小 $b$ 和最大 $d$,然后统计这个范围内的数字个数即可。

代码

我们可以使用 Python 语言实现上述思路:

from math import log2

def count_numbers_in_range(L, R):
    # 计数器
    count = 0

    # 枚举完美幂的底数
    for a in range(1, int(R ** 0.5) + 1):
        for c in range(1, int(R ** 0.25) + 1):
            # 如果 a^b + c^d 在区间 [L, R] 中,就增加计数器的值
            x = a ** 2 + c ** 4
            if L <= x <= R:
                count += 1
            if x > R:
                break
            
            for d in range(3, int(log2(R) / log2(c)) + 1):
                # 通过牛顿迭代求出满足 a^b + c^d >= L 的最小 b
                b = 1
                while a ** b + c ** d < L:
                    b *= 2
                while True:
                    db = (L - a ** b) // (a ** (b - 1) * log2(a))
                    if db == 0:
                        break
                    b += db

                # 如果 b <= d,我们只需要统计 a^b + c^d 即可
                if b <= d:
                    if L <= a ** b + c ** d <= R:
                        count += 1
                # 否则需要同时统计 a^b + c^d 和 a^d + c^b
                else:
                    if L <= a ** b + c ** d <= R:
                        count += 1
                    if L <= a ** d + c ** b <= R:
                        count += 1

    return count

该函数的时间复杂度为 $O(\sqrt{R} \log R \log \log R)$,可以在比较短的时间内处理较大的输入。