P1009 [NOIP 1998 普及组] 阶乘之和
算法分类:高精度计算运算
链接:洛谷OJ
题目描述
用高精度计算出 S = 1 ! + 2 ! + 3 ! + ⋯ + n ! S = 1! + 2! + 3! + \cdots + n! S=1!+2!+3!+⋯+n!( n ≤ 50 n \le 50 n≤50)。
其中 !
表示阶乘,定义为
n
!
=
n
×
(
n
−
1
)
×
(
n
−
2
)
×
⋯
×
1
n!=n\times (n-1)\times (n-2)\times \cdots \times 1
n!=n×(n−1)×(n−2)×⋯×1。例如,
5
!
=
5
×
4
×
3
×
2
×
1
=
120
5! = 5 \times 4 \times 3 \times 2 \times 1=120
5!=5×4×3×2×1=120。
输入格式
一个正整数 n n n。
输出格式
一个正整数 S S S,表示计算结果。
输入输出样例 #1
输入 #1
3
输出 #1
9
说明/提示
【数据范围】
对于 100 % 100 \% 100% 的数据, 1 ≤ n ≤ 50 1 \le n \le 50 1≤n≤50。
【其他说明】
注,《深入浅出基础篇》中使用本题作为例题,但是其数据范围只有 n ≤ 20 n \le 20 n≤20,使用书中的代码无法通过本题。
如果希望通过本题,请继续学习第八章高精度的知识。
NOIP1998 普及组 第二题
题解
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
class BigInt {
private:
vector<int> digits;
void trimLeadingZeros() {
while (digits.size() > 1 && digits.back() == 0) {
digits.pop_back();
}
}
public:
BigInt(const string& num = "0") {
if (num.empty()) {
digits = {0};
return;
}
for (int i = num.size() - 1; i >= 0; --i) {
if (!isdigit(num[i]))
throw invalid_argument("Invalid character in number string");
digits.push_back(num[i] - '0');
}
trimLeadingZeros();
}
// 加法运算符重载(核心算法)
BigInt operator+(const BigInt& other) const {
BigInt result;
result.digits.clear();
int carry = 0;
for (size_t i = 0;
i < max(digits.size(), other.digits.size()) || carry;
++i)
{
int sum = carry;
if (i < digits.size()) sum += digits[i];
if (i < other.digits.size()) sum += other.digits[i];
result.digits.push_back(sum % 10);
carry = sum / 10;
}
return result;
}
// 乘法运算符重载(核心算法)
BigInt operator*(const BigInt& other) const {
BigInt result; // 创建结果对象
// 预分配结果数组空间(两数位数之和,确保足够存储所有位数)
result.digits.resize(digits.size() + other.digits.size(), 0);
// 外层循环:遍历乘数的每一位(当前对象的每个digit)
for (size_t i = 0; i < digits.size(); ++i) {
int carry = 0; // 当前位的进位值
// 内层循环:遍历被乘数的每一位(other对象的digit)或处理剩余进位
for (size_t j = 0; j < other.digits.size() || carry; ++j) {
// 计算当前位的乘积总和:
// 1. 当前结果位已有的值(来自之前的计算)
// 2. 当前乘数位 × 被乘数位(如果存在)
// 3. 来自前一位的进位
long long product = result.digits[i + j] +
digits[i] * (j < other.digits.size() ? other.digits[j] : 0) +
carry;
// 更新当前结果位:取个位数
result.digits[i + j] = product % 10;
// 计算新的进位:取十位数(自动向下取整)
carry = product / 10;
}
}
// 去除结果中的前导零(例如 0 × 123 = 000 转换为 0)
result.trimLeadingZeros();
return result;
}
// 输出运算符重载(将存储的逆序数字转回正常顺序)
friend ostream& operator<<(ostream& os, const BigInt& num) {
for (int i = num.digits.size() - 1; i >= 0; --i) {
os << num.digits[i];
}
return os;
}
// 输入运算符重载(读取字符串并构造对象)
friend istream& operator>>(istream& is, BigInt& num) {
string input;
is >> input;
num = BigInt(input);
return is;
}
};
// 更新主函数测试乘法
int main() {
BigInt result = BigInt("0"); // 用于存储最终结果
BigInt temp = BigInt("1"); // 用于存储n!的值
int n;
cin >> n;
for(int i = 1; i <=n; i++){
BigInt a = BigInt(to_string(i)); // 将i从int转化为BigInt
temp = temp * a;
result = result + temp;
}
cout << result << endl;
return 0;
}