当前位置: 首页 > news >正文

阶乘求和全解析:从 Python 秒过到 C++ 手写高精度

1. 概述

在洛谷刷题时,我偶然点进了一道看起来非常“友善”的题目——P1009 阶乘求和。题面简单得不能再简单,只要求我们计算:

S = 1 ! + 2 ! + 3 ! + ⋯ + n ! ( 1 ≤ n ≤ 50 ) S = 1! + 2! + 3! + \dots + n! \quad (1 \leq n \leq 50) S=1!+2!+3!++n!1n50
在这里插入图片描述

看完题我心里一笑:这不就是个循环累加阶乘的问题?
没有数组处理,没有边界卡点,没有复杂输入输出格式 —— 简直是送分题。

我很快写好了 C++ 代码,自信地提交上去,然后……就没然后了。评测系统直接返回了“答案错误”的提示,而且是多个测试点都挂掉。更离谱的是,程序有时候还会输出一个负数

这让我顿时陷入沉思:
👉 明明代码逻辑是对的,为什么会错?
👉 到底是哪个环节出了问题?
👉 Python 同样逻辑就能通过,我的 C++ 到底差在哪?

于是我开始查资料、调试,最后发现问题出在 C++ 的整数精度限制上 —— 当 n 变大时,阶乘的值远远超出了 long long 能表示的范围,导致了溢出错误。

这次“看似简单”的翻车经历,也让我深入了解了高精度计算在刷题中的重要性,也顺便复习了一遍 Python 和 C++ 在处理大数时的差异和各自优势。

本文就以这道题为例,先介绍常规思路,再分析为什么它在 C++ 中会失败,然后提供两种可行的解决方案:

  • 用 Python,借助其原生支持的任意精度整数,轻松 AC
  • 用 C++,手写高精度加法与乘法,真正掌握底层实现

无论你是追求快速 AC,还是提升算法功底,这篇文章都希望能对你有所启发。

2. 常规 C++ 解法

我们都知道阶乘的基本实现方式非常简单,一个循环搞定:

#include<iostream>
using namespace std;long long accumulate_jc(int num){long long ans = 1;for(int i = 1; i <= num; i++){ans *= i;}return ans;
}int main(){int n;cin >> n;long long sum = 0;for(int i = 1; i <= n; i++){sum += accumulate_jc(i);}cout << sum << endl;return 0;
}

这个程序在 n=3 时输出 1!+2!+3!=1+2+6=9,结果没问题。可是当提交到洛谷的测评系统,在 n=50 时就不对劲了:结果错误,甚至出现负数!

3. 错误原因

long long 在 C++ 中的最大值约为 9.2 × 1 0 18 9.2 \times 10^{18} 9.2×1018,而 50! 的值约为:

50 ! ≈ 3.04 × 1 0 64 50! \approx 3.04 \times 10^{64} 50!3.04×1064

这远远超出了 long long 能表示的范围!因此,整数溢出 就成了导致程序错误的根本原因。

4. 用 Python 轻松应对(自动高精度)

你可能已经想到:Python 是不是能解决这个问题?答案是:完全可以!

def accumulate_jc(num):ans = 1for i in range(1, num+1):ans *= ireturn ansn = int(input())
total = 0
for i in range(1, n+1):total += accumulate_jc(i)
print(total)

为什么 Python 能轻松跑通?

因为 Python 的 int 类型本质上是任意精度整数,当数字变大时,底层会自动扩展位数,直到内存上限。

所以在处理高精度问题时,Python 是“作弊般”的存在,用起来很爽。

5. 解法二:C++ 高精度加法与乘法

如果你仍然坚持用 C++,那就必须自己实现高精度整数的加法与乘法。

5.1 思路简述

  • vector<int> 存储大整数的每一位(低位在前,高位在后);
  • 手动实现乘法(大整数 × 整数)和加法(两个大整数相加);
  • 循环计算每个阶乘,并用高精度累加到最终结果中。

5.2 高精度 C++ 实现代码

#include<iostream>
#include<vector>
using namespace std;// 高精度乘法:a × b(a 为 vector 表示的大数)
vector<int> multiply(vector<int>& a, int b) {vector<int> res;int carry = 0;for (int i = 0; i < a.size(); i++) {int temp = a[i] * b + carry;res.push_back(temp % 10);carry = temp / 10;}while (carry) {res.push_back(carry % 10);carry /= 10;}return res;
}// 高精度加法:a + b
vector<int> add(vector<int>& a, vector<int>& b) {vector<int> res;int carry = 0;int n = max(a.size(), b.size());for (int i = 0; i < n; i++) {int x = i < a.size() ? a[i] : 0;int y = i < b.size() ? b[i] : 0;int sum = x + y + carry;res.push_back(sum % 10);carry = sum / 10;}if (carry) res.push_back(carry);return res;
}int main() {int n;cin >> n;vector<int> sum = {0}; // 初始结果为 0for (int i = 1; i <= n; i++) {vector<int> fac = {1}; // 初始化阶乘为 1for (int j = 2; j <= i; j++) {fac = multiply(fac, j); // fac *= j}sum = add(sum, fac); // sum += fac}// 逆序输出结果(高位在前)for (int i = sum.size() - 1; i >= 0; i--) {cout << sum[i];}cout << endl;return 0;
}

这次“翻车”让我深刻意识到:刷题过程中踩坑才是最好的学习机会

6. 相似题目推荐

如果你在解决这类高精度问题的过程中觉得意犹未尽,或者希望继续练习相关技巧,LeetCode 上也有不少非常典型的高精度模拟题目可以作为延伸练习。

这些题虽然看起来是“字符串处理”或者“链表处理”,但本质上考察的依然是模拟大整数的加法、乘法逻辑,与本文中的高精度思路一脉相承:

  • 字符串相加
    👉 Add Strings(字符串相加)

    给定两个表示非负整数的字符串,返回它们的和。需要模拟竖式加法,不可使用内建高精度库。

  • 字符串相乘
    👉 Multiply Strings(字符串相乘)

    两个超大整数的乘法模拟,经典的高精度乘法题。完全不能用内置大整数库,必须手写处理进位和位数。

  • 两数相加
    👉 Add Two Numbers(两数相加)

    使用链表按位表示两个非负整数,返回它们的和。考察链表处理+进位逻辑,适合作为高精度入门题。

  • 从“字符串相加”入手,掌握进位加法;

  • 再尝试“字符串相乘”,挑战进位乘法和模拟乘法竖式计算;

  • 最后试试“链表加法”,理解数据结构 + 高精度结合的题型。

如果你已经掌握了本文的高精度思路,尝试用 C++ 手动实现这些 LeetCode 题,也是一种非常不错的算法训练路径。高精度计算虽然繁琐,但能极大提升你对“模拟类题目”的掌控力,尤其在比赛、面试或笔试中,这类题型可谓常客。

相关文章:

  • 【Redis#4】Redis 数据结构 -- String类型
  • 【如何实现分布式压测中间件】
  • 什么是区块哈希(Block Hash)
  • 图片元数据与防篡改技术指南
  • 编写c++程序分别在x86和arm架构的ubuntu下访问CAN 接口设备
  • 80%的知识库场景选择FastGPT,20%的复杂场景选择Dify
  • 设计的“第一性原理”:从Photoshop与Premiere Pro的AI革新谈起
  • 具身智能系列教程——(三)gazebo环境配置与强化学习训练
  • 【git】撤销操作
  • C# 委托(调用带引用参数的委托)
  • 链表题解——删除链表的倒数第 N 个结点【LeetCode】
  • 鸿蒙5:自定义构建函数
  • 聊聊横向移动中的实际技术点 ----- ResponderSMB
  • matlab 渐进三角网(PTD)地面滤波(基础版)
  • Django ORM 2. 模型(Model)操作
  • 机器学习7——神经网络上
  • 高频SQL50题 第九天 | 1164. 指定日期的产品价格、1204. 最后一个能进入巴士的人、1907. 按分类统计薪水
  • pytorch--模型训练的一般流程
  • 1 Studying《Computer Vision: Algorithms and Applications 2nd Edition》11-15
  • MySQL之全场景常用工具链