题解:学而思编程 二元函数

【题目来源】

学而思编程:二元函数

【题目描述】

能用非负整数 \(a\)\(b\) 表示为:\(X=a^3+a^2b+ab^2+b^3+a^2+ab+b^2\) 形式的整数 \(X\) 称作“特别数”。给你一个非负整数 \(n\),求大于等于 \(n\) 的最小的“特别数”

【输入】

\(1\) 个整数 \(n\)

【输出】

大于等于 \(n\) 的最小的“特别数”

【输入样例】

9

【输出样例】

12

【核心思想】

  1. 问题分析:给定非负整数 \(n\),求满足 \(X = a^3 + a^2b + ab^2 + b^3 + a^2 + ab + b^2\)\(a, b \geq 0\))且 \(X \geq n\) 的最小整数 \(X\)。这是一个双指针枚举 + 单调性优化问题,关键在于利用 \(f(a, b)\) 关于 \(a\)\(b\) 的单调性,避免 \(O(N^2)\) 的暴力枚举。

  2. 算法选择

    • 双指针(对向扫描):固定 \(a\) 递增,\(b\) 递减,利用单调性保证每个 \((a, b)\) 对最多被访问一次
    • 单调性优化\(f(a, b)\) 关于 \(a\)\(b\) 均单调递增,因此当 \(a\) 增大时,满足 \(f(a, b) \geq n\)\(b\) 只会减小或不变
  3. 关键步骤

    • 初始化:读取目标值 \(n\),初始化 minn = +\infty
    • 设定枚举范围\(a\)\(0\)\(10^6\)\(b\) 初始化为 \(10^6\)
    • 双指针扫描
      • 遍历 \(a\)\(0\)\(10^6\)(递增):
        • f(a, b) \geq nb \geq 0 时循环:
          • minn = \min(minn, f(a, b)):更新满足条件的最小特别数
          • b--\(b\) 递减,寻找更小的可能值
        • 此时对于当前 \(a\)\(b\) 已减到使 \(f(a, b) < n\)\(b < 0\)
      • 进入下一个 \(a\) 时,由于 \(a\) 增大,\(f(a, b)\) 增大,之前使 \(f(a, b) < n\)\(b\) 可能再次满足条件,但 \(b\) 只会继续减小
    • 输出 minn
  4. 时间/空间复杂度

    • 时间复杂度:\(O(10^6)\)\(a\) 最多遍历 \(10^6\) 次,\(b\) 总共最多递减 \(10^6\) 次,每个 \((a, b)\) 对最多被访问一次
    • 空间复杂度:\(O(1)\),仅需常数额外空间
  5. 双指针单调性优化的核心思想

    • 单调性分析\(f(a, b)\) 关于 \(a\)\(b\) 均单调不减(各项均为非负整数的幂次和乘积),因此固定 \(a\) 时,\(f(a, b)\)\(b\) 增大而增大
    • 对向扫描策略\(a\) 从小到大递增,\(b\) 从大到小递减。对于每个 \(a\),找到满足 \(f(a, b) \geq n\) 的最小 \(b\) 区间,然后 \(b\) 继续减小供下一个 \(a\) 使用
    • 避免重复计算:由于 \(b\) 只减不增,两个指针总共移动不超过 \(2 \times 10^6\) 步,将 \(O(N^2)\) 降为 \(O(N)\)
    • 边界处理\(b\) 可能减到 \(0\) 以下,循环条件 b >= 0 保证合法性;minn 初始化为 LLONG_MAX 确保第一次更新有效
    • 适用于"二元函数求满足约束的最小值"问题,当函数关于两个变量均单调时,双指针可将平方级枚举优化为线性级

【解题思路】

【算法标签】

数学

【代码详解】

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n;
ll minn = 9223372036854775807;  // 2^63-1,long long的最大值

// 计算函数f(a,b)
ll f(ll a, ll b)
{
    return a*a*a + a*a*b + a*b*b + b*b*b + a*a + a*b + b*b;
}

int main()
{
    cin >> n;  // 输入目标值

    // 初始化b为最大值
    ll b = 1000000;

    // 遍历a从0到1000000
    for (ll a = 0; a <= 1000000; a++) {
        // 当f(a,b) >= n且b >= 0时,递减b
        while (f(a, b) >= n && b >= 0) {
            minn = min(minn, f(a, b));  // 更新最小值
            b--;  // 减小b
        }
    }

    cout << minn;  // 输出满足条件的最小f(a,b)
    return 0;
}

【运行结果】

9
12
posted @ 2026-07-04 12:16  团爸讲算法  阅读(4)  评论(0)    收藏  举报