四平方和定理C++高效解法及字典序最小输出策略
这个问题是典型的**四平方和定理**应用,需要找出满足 `a² + b² + c² + d² = N` 且 `0 ≤ a ≤ b ≤ c ≤ d` 的**字典序最小**的解。 ## 🧠 解题思路 **核心思想**:为了得到字典序最小的解,我们**从小到大**枚举 `a`、`b`、`c`,然后根据剩余值判断是否能找到合法的 `d`。 ### 📐 数学推导 - 由于 `0 ≤ a ≤ b ≤ c ≤ d`,且要求字典序最小,所以 `a`、`b`、`c` 都应尽量小。 - 当枚举到 `a`、`b`、`c` 后,剩余值为 `rem = N - a² - b² - c²`。 - 需要验证 `rem` 是否为完全平方数,且满足 `d ≥ c`。 - 由于 `N < 5×10⁶`,`d` 的最大值约为 `√(5×10⁶) ≈ 2236`,因此三重循环的复杂度在可接受范围内。 ### ⏱️ 复杂度分析 - 最坏情况下,`a`、`b`、`c` 都从 `0` 到 `√N` 枚举,三重循环约为 `(√N)³ = N^1.5`,对于 `N = 5×10⁶` 约为 `10^10`,**可能超时**。 - **优化**:提前用哈希表(或布尔数组)存储所有可能的 `c² + d²` 值及其对应的 `c`,将问题转化为两数之和。 ## 💻 C++ 代码实现(优化版) ```cpp #include <iostream> #include <cmath> using namespace std; int main() { int N; cin >> N; // 哈希表:记录 sum = c² + d² 的最小 c 值(保证字典序最小) // 由于 N < 5×10⁶,sum 最大为 N,数组大小足够 int hashTable[5000001] = {0}; // 初始化为0,但需要区分“未记录”和“c=0”的情况 // 使用 -1 表示未记录 for (int i = 0; i <= 5000000; i++) hashTable[i] = -1; // 预计算所有 c² + d² 的组合,存储最小的 c for (int c = 0; c * c <= N; c++) { for (int d = c; c * c + d * d <= N; d++) { int sum = c * c + d * d; if (hashTable[sum] == -1) { hashTable[sum] = c; // 只记录第一次(c最小)的情况 } } } // 枚举 a 和 b for (int a = 0; a * a <= N; a++) { for (int b = a; a * a + b * b <= N; b++) { int rem = N - a * a - b * b; // 查表找是否存在 c² + d² = rem if (hashTable[rem] != -1) { int c = hashTable[rem]; // 验证 d 是否为整数且 >= c int d = sqrt(rem - c * c); if (c * c + d * d == rem && c <= d) { // 需要确保字典序:a ≤ b ≤ c ≤ d if (b <= c) { cout << a << " " << b << " " << c << " " << d << endl; return 0; } } } } } return 0; } ``` ## 📝 代码关键点解析 | 部分 | 说明 | |------|------| | **预计算哈希表** | 遍历所有 `c ≤ d` 的组合,记录 `c² + d²` 对应的最小 `c` 值 | | **数组大小** | `N < 5×10⁶`,所以数组开到 `5000001` 即可覆盖所有可能和 | | **字典序保证** | 由于 `a`、`b` 从小到大枚举,且哈希表记录的是最小的 `c`,自然得到字典序最小解 | | **边界检查** | 使用 `c * c + d * d <= N` 提前终止内层循环,避免无用计算 | ## 🚀 算法优化说明 **为什么哈希表能大幅提速?** - 原始三重循环时间复杂度为 `O(N^1.5)`,对于 `5×10⁶` 会超时。 - 优化后:预计算 `O(N)`,枚举 `a`、`b` 为 `O(N)`,总复杂度 **O(N)**。 - 同时保证哈希表中记录的是**最小的 `c`**,从而确保最终结果是字典序最小的。 ## ⚠️ 注意事项 1. **整数溢出**:`c * c` 当 `c` 较大时可能超过 `int` 范围,建议使用 `long long` 或提前判断 `c <= sqrt(N)`。 2. **边界条件**:`N = 0` 时输出 `0 0 0 0`,本题输入为正整数所以不需特殊处理。 3. **哈希表初始化**:不能使用 `0` 作为“未记录”标记,因为合法的 `c` 可能为 `0`,需用 `-1` 或单独布尔数组。 ######[AI写代码神器 | 1264点数解答 | 2026-08-16 09:43:00]
- 编程揭秘角谷猜想:验证过程、代码实现及注意要点(字节豆包 | 361点数解答 | 2025-11-02 10:40:33)112
- 巴黎奥运:中国女排淘汰赛对决土耳其,朱婷成致胜关键!(字节豆包 | 448点数解答 | 2024-08-06 15:59:48)245
- Python:创建文件、统计单词频率并按字母排序输出的实现(GPT | 697点数解答 | 2024-05-30 10:30:24)319
- Python 实现:将 “k1:1| k2:2| k3:3” 字符串转换为字典并输出(讯飞星火 | 178点数解答 | 2024-06-23 21:53:50)300
- 旅行售货员问题:详细步骤剖析与贪心算法Python代码实现(字节豆包 | 444点数解答 | 2024-12-17 03:32:59)378
- Dev C++ 实现旅行售货员问题:最小路程路线代码与详细解析 (字节豆包 | 448点数解答 | 2024-12-17 03:33:42)257
- Maxscript 替代 C# 字典与 List:数组使用指南及注意要点(字节豆包 | 183点数解答 | 2025-01-13 22:53:17)347
- C++ 求解 P1020 小核桃与删除字符串问题:双指针与枚举策略 (字节豆包 | 330点数解答 | 2026-02-07 18:40:10)120
- C++编程:解决大白能量痕迹距离范围问题及开发注意要点(字节豆包 | 306点数解答 | 2025-11-21 19:18:11)90
- C++程序:依据感应器数字输出能量痕迹与小队距离范围(DeepSeek | 88点数解答 | 2025-12-21 16:10:13)97
- 编程解谜:根据感应器数字确定大白能量痕迹与小队距离范围(字节豆包 | 67点数解答 | 2026-01-03 19:14:14)79
- 玄铁迷宫寻大白:凭感应器数字定能量痕迹距离的C++程序揭秘(字节豆包 | 114点数解答 | 2026-01-03 19:14:26)100