算法练习:P1009 [NOIP 1998 普及组] 阶乘之和 高精度计算运算

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 n50)。

其中 ! 表示阶乘,定义为 n ! = n × ( n − 1 ) × ( n − 2 ) × ⋯ × 1 n!=n\times (n-1)\times (n-2)\times \cdots \times 1 n!=n×(n1)×(n2)××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 1n50

【其他说明】

注,《深入浅出基础篇》中使用本题作为例题,但是其数据范围只有 n ≤ 20 n \le 20 n20,使用书中的代码无法通过本题。

如果希望通过本题,请继续学习第八章高精度的知识。

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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值