📌  相关文章
📜  Q 查询中位于 [L, R] 范围内的所有完美立方体的总和(1)

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

查询中位于 [L, R] 范围内的所有完美立方体的总和

在计算几何中,我们称一个立方体为完美立方体,当且仅当它的所有边长都是整数。

现在,给出一个区间 $[L, R]$,请你计算中位于该区间内的所有完美立方体的总和。具体来说,就是找到所有边长为整数的立方体,且满足 $L\leq a,b,c\leq R$ 的完美立方体 $(a,b,c)$,并计算它们的立方和。

为了解决这个问题,我们可以采用枚举边长的方法,对于所有满足条件的边长,计算立方体的立方和。但是,这种方法时间复杂度显然过高。事实上,我们可以通过一些巧妙的数学方法,大大减少计算的次数。

首先注意到,如果一个立方体 $(a,b,c)$ 是完美立方体,那么它的体积 $abc$ 一定是一个完全平方数,即存在 $k\in \textbf{N}$,使得 $abc=k^2$。

我们再来看另一个性质:假设 $n$ 是一个正整数,那么它的因数个数 $d(n)$ 一定是偶数或奇数。具体来说,我们可以构造 $n$ 的所有因数对,比如说:

$${1,n},{2,\dfrac{n}{2}},{3,\dfrac{n}{3}},\dots,{a,b},\dots,{\sqrt{n},\sqrt{n}}$$

这里的 $a,b$ 是相互不同且满足 $ab=n$ 的两个正整数。很容易证明这样的因数对恰好有 $\lfloor\frac{d(n)}{2} \rfloor$ 个,即因数个数是偶数。

现在,我们以此为基础思路,考虑对于每个满足 $L\leq a,b,c\leq R$ 的三元组 $(a,b,c)$,计算它们的立方和 $a^3b^3c^3$ 的贡献。具体地,如果 $abc=k^2$,那么这个三元组 $(a,b,c)$ 的贡献就是 $k^2$。而 $k^2$ 的贡献,我们可以拆分成多个因数数量相等的完全平方数。比如说,$k^2$ 的因数对 ${i,\frac{k^2}{i}}$ 是一个完全平方数当且仅当 $i$ 是一个完全平方数。因此,我们只需要统计区间 $[l,r]$ 中有多少个完全平方数 $n$ 满足 $L\leq \sqrt[3]{n}\leq R$,并令它们的和为 $S$,那么所有的完美立方体的立方和就是 $\dfrac{S}{2}$。

下面是具体的实现思路:

  1. 考虑如何统计满足条件的完全平方数。首先将区间 $[L,R]$ 作差,即令 $R-R_0 = r, L-L_0 = l$,则我们现在需要统计满足 $L_0+l \leq i^3 \leq R_0+r$ 的完全平方数数量。我们可以使用整除分块,将 $R_0$ 到 $R_0+r$ 这个区间内的数分成 $\sqrt{R_0}$ 个块,每个块内包含 $\sqrt{R_0}$ 个数。对于每个块,我们考虑它内部的所有数的立方根,将它们按从小到大的顺序排列,再加上 $L_0$,即得到了 $[L_0+l,R_0+r]$ 中所有符合条件的立方根。然后,我们对所有区间内的立方根,取整并计算它们出现的次数,就可以得到满足条件的完全平方数数量。

  2. 计算贡献。对于每个满足条件的立方根 $\sqrt[3]{n}$,我们计算它对应的 $k^2$ 以及它的因数个数 $d(\sqrt[3]{n})$,并将 $k^2$ 加入到 $S$ 中。最后输出 $\dfrac{S}{2}$ 即可。

下面是代码实现:

const int maxn = 1e6 + 5;
int v[maxn], cnt[maxn], a[maxn], b[maxn], c[maxn];
int L, R, idx;

int main() {
    scanf("%d%d", &L, &R);
    int l = ceil(pow(L, 1.0 / 3)), r = floor(pow(R, 1.0 / 3));
    for(int i = l; i <= r; i++){
        a[idx] = b[idx] = c[idx] = i;
        idx++;
    }
    l = max(1, l - 1);
    r = sqrt(R);
    for(int i = 1; i <= idx; i++){
        for(int j = i; j <= idx; j++){
            int t = a[i - 1] * a[j - 1];
            if(t > r) break;
            for(int k = j; k <= idx; k++){
                ll p = (ll)t * c[k - 1];
                if(p > R || p < L) continue;
                int q = pow(p, 1.0 / 3) + 0.5;
                if(p != 1ll * q * q * q) continue;
                int tmp = pow(c[k - 1], 1.0 / 3) + 0.5;
                cnt[tmp - L]++;
                v[tmp - L] += q;
            }
        }
    }
    ll ans = 0;
    for(int i = L; i <= R; i++){
        if(cnt[i - L]) {
            ans += 1ll * cnt[i - L] * (v[i - L] >> 1);
        }
    }
    printf("%lld\n", ans);
    return 0;
}

其中,变量 LR 分别表示给定区间 $[L, R]$,变量 a,b,c 代表三元组 $(a,b,c)$ 中的三个边长,变量 idx 代表考虑的三元组数量。变量 v[i-L] 表示完全平方数 $\sqrt{n}=i$,对应的 $k^2$ 的和。变量 cnt[i-L] 代表完全平方数 $\sqrt{n}=i$ 的个数。函数 pow(x, 1.0 / 3) 表示求 $x$ 的立方根,函数 pow(x, 1.0 / 2) 表示求 $x$ 的平方根,函数 ceil(x) 表示向上取整,函数 floor(x) 表示向下取整。