题解:学而思编程 二元函数
【题目来源】
学而思编程:二元函数
【题目描述】
能用非负整数 \(a\),\(b\) 表示为:\(X=a^3+a^2b+ab^2+b^3+a^2+ab+b^2\) 形式的整数 \(X\) 称作“特别数”。给你一个非负整数 \(n\),求大于等于 \(n\) 的最小的“特别数”
【输入】
\(1\) 个整数 \(n\)
【输出】
大于等于 \(n\) 的最小的“特别数”
【输入样例】
9
【输出样例】
12
【核心思想】
-
问题分析:给定非负整数 \(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)\) 的暴力枚举。
-
算法选择:
- 双指针(对向扫描):固定 \(a\) 递增,\(b\) 递减,利用单调性保证每个 \((a, b)\) 对最多被访问一次
- 单调性优化:\(f(a, b)\) 关于 \(a\) 和 \(b\) 均单调递增,因此当 \(a\) 增大时,满足 \(f(a, b) \geq n\) 的 \(b\) 只会减小或不变
-
关键步骤:
- 初始化:读取目标值 \(n\),初始化
minn = +\infty - 设定枚举范围:\(a\) 从 \(0\) 到 \(10^6\),\(b\) 初始化为 \(10^6\)
- 双指针扫描:
- 遍历 \(a\) 从 \(0\) 到 \(10^6\)(递增):
- 当
f(a, b) \geq n且b \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\) 只会继续减小
- 遍历 \(a\) 从 \(0\) 到 \(10^6\)(递增):
- 输出
minn
- 初始化:读取目标值 \(n\),初始化
-
时间/空间复杂度:
- 时间复杂度:\(O(10^6)\),\(a\) 最多遍历 \(10^6\) 次,\(b\) 总共最多递减 \(10^6\) 次,每个 \((a, b)\) 对最多被访问一次
- 空间复杂度:\(O(1)\),仅需常数额外空间
-
双指针单调性优化的核心思想:
- 单调性分析:\(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
浙公网安备 33010602011771号