判断是否存在正整数对 (x,y) 满足 x3−y3=N,若存在则输出其中一对,否则输出 -1。N<1e18;
核心公式变形:x3−y3=(x−y)(x2+xy+y2)=N由于 x>y≥1,可令 d=x−y(d≥1),则 x=y+d。代入后得:N=d⋅(3y2+3dy+d2)
因此,d 必须是 N 的约数,且满足:3y2+3dy+(d2−N/d)=0这是关于 y 的一元二次方程,可通过判别式判断是否存在正整数解。
解题步骤
-
枚举可能的 d:d 是 N 的约数,且 d≤3N(因 x3>N,故 x≤N1/3+1)。
-
检查约数条件:对每个 d,若 Nmodd!=0,直接跳过。
-
求解二次方程:令 m=N/d,方程化为 3y2+3dy+(d2−m)=0,计算判别式 Δ=12m−3d2。
-
验证正整数解:若 Δ 是完全平方数且 y 为正整数,则 x=y+d 是解。
#include <iostream>
#include <cmath>
using namespace std;
using ll = long long;int main() {
ll N;
cin >> N;// 枚举 d 的可能值,上限为 N^(1/3) + 2(避免遗漏) for (ll d = 1; d * d * d <= N + 2; ++d) { if (N % d != 0) continue; // d 必须是 N 的约数 ll m = N / d; // 计算判别式 Δ = 12m - 3d² ll delta = 12 * m - 3 * d * d; if (delta < 0) continue; // 无实根 // 检查 Δ 是否为完全平方数 ll sqrt_delta = sqrt(delta); if (sqrt_delta * sqrt_delta != delta) continue; // 检查 y 是否为正整数:y = [-3d + sqrt(delta)] / 6 if ((-3 * d + sqrt_delta) % 6 != 0) continue; ll y = (-3 * d + sqrt_delta) / 6; if (y <= 0) continue; // 找到有效解 ll x = y + d; cout << x << " " << y << endl; return 0; } // 未找到解 cout << -1 << endl; return 0;}
代码说明
- 枚举范围:d 的上限设为 N1/3+2,因 x3≈N,故 x 不会远大于 N1/3,有效减少枚举量。
- 判别式检查:确保二次方程有实根,且根为正整数。
- 效率:时间复杂度为 O(N1/3),对 N≤1018 而言,N1/3≈106,枚举过程高效。
但是由于数据过大,在面对直接平方时很可能直接炸,使用二分法可以进行优化
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
// 二分法求解二次方程ax² + bx + c = 0的非负整数解
// 原理:二次函数f(x)=ax²+bx+c开口向上(a=3>0),在正半轴单调递增,可用二分定位根
ll sol(ll a, ll b, ll c) {
ll l = 0; // 左边界:可能的最小解(0)
ll r = 600000001; // 右边界:足够大的上限(覆盖1e18范围内的可能解)
// 二分查找:当区间长度大于1时继续缩小范围
while (r - l > 1) {
ll mid = (l + r) / 2; // 中间值(避免溢出的写法)
// 计算f(mid),若<=0说明根在右侧,移动左边界
if (a * mid * mid + b * mid + c <= 0)
l = mid;
else // 否则根在左侧,移动右边界
r = mid;
}
// 检查左边界是否为方程的解(必须严格等于0)
if (a * l * l + b * l + c == 0)
return l; // 找到有效解
return -1; // 无有效解
}
int main() {
ll n;
cin >> n; // 输入目标值N
// 枚举可能的d(d是x-y的差值,x = k + d,y = k)
// d的上限为N^(1/3):因d³ <= N(否则方程左侧会超过N)
for (ll d = 1; d * d * d <= n; ++d) {
// d必须是N的约数(由立方差公式推导得出)
if (n % d != 0)
continue;
// 计算m = N/d,将原方程转化为3k² + 3dk + (d² - m) = 0
ll m = n / d;
// 调用二分函数求解k,传入二次方程系数a=3, b=3d, c=d² - m
ll k = sol(3, 3 * d, d * d - m);
// 若k是正整数,则找到一组解(x,y)=(k+d, k)
if (k > 0) {
cout << k + d << " " << k << endl;
return 0; // 找到解后直接退出
}
}
// 枚举完所有可能的d仍无有效解,输出-1
cout << -1 << endl;
return 0;
}