利用数的变形简化大规模问题#数论

判断是否存在正整数对 (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 的一元二次方程,可通过判别式判断是否存在正整数解。

解题步骤

  1. 枚举可能的 d:d 是 N 的约数,且 d≤3N(因 x3>N,故 x≤N1/3+1)。

  2. 检查约数条件:对每个 d,若 Nmodd!=0,直接跳过。

  3. 求解二次方程:令 m=N/d,方程化为 3y2+3dy+(d2−m)=0,计算判别式 Δ=12m−3d2。

  4. 验证正整数解:若 Δ 是完全平方数且 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;
}
相关推荐
多思考少编码18 分钟前
PAT甲级真题1001 - 1005题详细题解(C++)(个人题解)
c++·python·最短路·pat·算法竞赛
极客智造2 小时前
C++ 标准 IO 流全详解:cin /cout/get /getline 原理、用法、区别与避坑
c++·io
charlie1145141912 小时前
嵌入式C++工程实践第20篇:GPIO 输入模式内部电路 —— 芯片是如何“听“到外部信号的
开发语言·c++·stm32·单片机
aini_lovee2 小时前
多目标粒子群优化(MOPSO)双适应度函数MATLAB实现
人工智能·算法·matlab
yong99902 小时前
图像融合与拼接:完整MATLAB工具箱
算法·计算机视觉·matlab
春风不语5052 小时前
深入理解主成分分析(PCA)
算法
apollowing2 小时前
启发式算法WebApp实验室:从搜索策略到群体智能的能力进阶(二十二)
算法·启发式算法·web app
晚枫歌F2 小时前
最小堆定时器
数据结构·算法
云原生指北2 小时前
你的数据正在喂养 AI:从 Atlassian 公告,看科技平台的数据训练默认政策
笔记
Lumos_7773 小时前
Linux -- 线程
java·jvm·算法