📅  最后修改于: 2023-12-03 15:04:43.077000             🧑  作者: Mango
在计算几何中,我们称一个立方体为完美立方体,当且仅当它的所有边长都是整数。
现在,给出一个区间 $[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}$。
下面是具体的实现思路:
考虑如何统计满足条件的完全平方数。首先将区间 $[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]$ 中所有符合条件的立方根。然后,我们对所有区间内的立方根,取整并计算它们出现的次数,就可以得到满足条件的完全平方数数量。
计算贡献。对于每个满足条件的立方根 $\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;
}
其中,变量 L
和 R
分别表示给定区间 $[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)
表示向下取整。