D - Cubes
原题链接
题意简述
给定一个正整数 N N N,判断是否存在正整数对 ( x , y ) (x,y) (x,y),使得 x 3 − y 3 = N ( N ∈ [ 1 , 1 e 18 ] ) x^{3} - y^{3} = N(N ∈ [1,1e18]) x3−y3=N(N∈[1,1e18])
思路
数据规模提示这题必须用数学方法才能通过所有测试点。
不难想到立方差公式
x
3
−
y
3
=
(
x
−
y
)
(
x
2
+
x
y
+
y
2
)
x^{3} - y^{3} = (x - y) (x^{2} + xy + y^{2})
x3−y3=(x−y)(x2+xy+y2)
可以考虑根据这个式子枚举
x
−
y
x-y
x−y 。
设
d
=
x
−
y
d = x - y
d=x−y
则有
x
=
d
+
y
x = d + y
x=d+y
代入原式,有
x
2
+
x
y
+
y
2
=
3
y
2
+
3
d
y
+
d
2
x^{2} + xy + y^{2} = 3y^{2} + 3dy + d^{2}
x2+xy+y2=3y2+3dy+d2
也就是说
3
y
2
+
3
d
y
+
d
2
=
N
d
3y^{2} + 3dy + d^{2}=\frac{N}{d}
3y2+3dy+d2=dN
设正整数
k
=
N
d
k = \frac{N}{d}
k=dN,
d
d
d 是已知常数,将原式展开、整理成关于
y
y
y 一元二次方程形式:
3
y
2
+
3
d
y
+
d
2
−
k
=
0
3y^{2} + 3dy + d^{2} - k = 0
3y2+3dy+d2−k=0
显然该方程有解
由一元二次方程根的判别式
Δ
=
b
2
−
4
a
c
\Delta =\mathop{{b}}\nolimits^{{2}}-4ac \\
Δ=b2−4ac
对于本题
a
=
3
,
b
=
3
d
,
c
=
d
2
−
k
a=3,b=3d,c=d^{2}-k
a=3,b=3d,c=d2−k
代入,整理得
Δ
=
−
3
d
2
+
12
k
≥
0
\Delta = -3d^{2} + 12k\ge0
Δ=−3d2+12k≥0
又因为
k
=
N
d
k = \frac{N}{d}
k=dN,解不等式,得
d
≤
4
N
3
d \le \sqrt[3]{4N}
d≤34N
那么,得出结论:枚举
d
d
d 的范围为
[
1
,
4
N
3
]
[1,\sqrt[3]{4N}]
[1,34N]
对于本题极端情况, d ≤ 1587401.052 d\le 1587401.052 d≤1587401.052 可以通过。
接下来考虑怎么解方程。
由于枚举时 d d d 本身就是正整数,只需考虑 y y y 有无正整数解就可以了,只要找到一个合法的 y y y , x x x 也就可以确定,问题解决。
对于原方程,显然有
y
=
−
3
d
+
Δ
6
y ={-3d + \sqrt{\Delta}\over 6}
y=6−3d+Δ
先实现一个函数判断
Δ
\sqrt\Delta
Δ 是不是整数,再判断
y
y
y 是不是整数就可以了。
综上, O ( 4 N 3 ) O(\sqrt[3]{4N}) O(34N) 的枚举, O ( 1 ) O(1) O(1) 的判断,本题可以通过。
至于如何求出 4 N 3 \sqrt[3]{4N} 34N ,根据单调性二分 m a x d max_d maxd 即可
注意无解要输出 − 1 -1 −1
代码实现
注意在判定 Δ \Delta Δ 是不是平方数时用了二分的方法,主要是 s q r t sqrt sqrt 函数在如此巨大的数据规模下可能会精度丢失,二分更稳健。
为了安全,基本所有变量都使用 unsigned long long,尽管有的不需要。
#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
ull get_max_d(ull N){
N <<= 2;//N * 4
//N开三次方后一定在int范围内,不必开longlong
ull l = 1,r = 1587402,mid,ans;
//r没必要像我开的这么极限,当然这样可以防止爆longlong
while(l <= r){
mid = l + r >> 1;
ull d = 1ll * mid * mid * mid;
if(d <= N){
ans = mid;
l = mid + 1;
}else r = mid - 1;
}
return ans;
}
//计算平方根
long long compute_sqrt(ull del) {
ull l = 1, r = sqrt(del) + 1;
while (l <= r) {
ull mid = (l + r) / 2;
if (mid * mid == del) return mid;
else if (mid * mid < del) l = mid + 1;
else r = mid - 1;
}
return -1;
}
int main(){
ull N;
cin >> N;
//二分求解d的最大值
ull max_d = get_max_d(N);
//枚举d
for(int d = 1;d <= max_d;d++){
//d不是N的因子,必无解
if(N % d) continue;
ull del = -3ll * d * d + 12 * N / d;
ull m = compute_sqrt(del);//判断sqrt(del)是否是整数
if (m == -1) continue;
//numerator:分子
ull numerator = -3 * d + m;
if(numerator <= 0) continue;
if(numerator % 6) continue;
//找到可行解
ull y = numerator / 6;
if(y <= 0) continue;
ull x = d + y;
if(x < y) swap(x,y);
cout << x << " " << y << endl;
return 0;
}
cout << -1 << endl;
return 0;
}
好题。
739

被折叠的 条评论
为什么被折叠?



