洛谷刷题 P1009 [NOIP1998 普及组] 阶乘之和

题目跳转:P1009 [NOIP1998 普及组] 阶乘之和

思路

本题主要考察高精度加法与高精度乘法。

高精度是什么

在科学计算中,我们往往要计算一个几百亿大或者需要精确到小数点后几百位的数。这些数字远远超过了程序语言自带的数据类型,此时我们需要一种不同的记录数据的方式,即用字符串记录数据。

比如,我们用字符串记录1234这个数字时,我们会构造一个char 数组 listA,然后令listA [0] = ‘4’,listA [1] = ‘3’,listA [2] = ‘2’,listA [3] = ‘1’,此时我们是按反方向存储了1234,至于为何,接下来会说明,接着我们用相同方式,用listB存储9876。

高精度加法

首先我们回顾一下我们平时列竖式计算加法的过程。我们的基本思想是按位计算,结果的每一位是两者相应位数相加再加上上一位的进位。

比如我们来算一下上面的例子,我们用char数组result来存储结果,用int r 记录进位,用int temp_sum记录每一位相加和。首先我们计算listA[0]+listB[0],即temp_sum = listA[0]-‘0’ + listB[0] - ‘0’;然后计算余数,r = temp_sum /10;计算存入result中的数,temp_sum = temp_sum % 10,result.push(temp+‘0’)。如此循环

在此过程中,我们需要注意几种情况,一种是在计算结束后还有余数(突破最高位),我们需要将余数也按十进制放入result。另一种是在加法过程中,出现了一个加数先加完的情况,如2位数加4位数,因此我们在temp_sum计算时,需要进行判断

下面给出代码演示

// 高精度加法
vector<char> sum(vector<char> temp, vector<char> ans)
{
    int len1 = temp.size();
    int len2 = ans.size();
    int len = max(len1, len2); // 取最大长度
    int temp_sum = 0;   // 每位数的和
    int r = 0;          // 进位
    vector<char> res;    // 结果

    for (int i = 0; i < len; i++)
    {
        // 每位数的和
        if (i < len1)  // temp里面还有数
            temp_sum += temp[i] - '0';
        if (i < len2)  // ans里面还有数
            temp_sum += ans[i] - '0';
        
        temp_sum += r;      // 加上进位
        r = temp_sum / 10;  // 更新进位 
        res.push_back(temp_sum % 10 + '0');
        temp_sum = 0;  // 重置为0用于下一个循环
    }

    if (r != 0) // 如果有进位
    {
        res.push_back(r + '0');
    }

    return res;
}

高精度数与int乘法

在这道题中,我们的阶乘可以从上一个阶乘结果基础上乘一个int类型数得到,主要思想与加法类似,就是高精度的每位乘上乘数加上上一位的进位,得到result对应位数上的数字

下面给出代码演示

// 高精度乘法
vector<char> multiply(vector<char> temp, int n)
{
    int len = temp.size();
    int temp_sum = 0;
    int r = 0;
    vector<char> res;

    for (int i = 0; i < len; i++)
    {
        temp_sum = (temp[i] - '0') * n + r;
        r = temp_sum / 10;
        res.push_back(temp_sum % 10 + '0');
    }

    while (r != 0)  // 如果有进位
    {
        res.push_back(r % 10 + '0');
        r /= 10;
    }

    return res;
}

AC代码

#include<iostream>
#include<vector>
using namespace std;

// 高精度加法
vector<char> sum(vector<char> temp, vector<char> ans)
{
    int len1 = temp.size();
    int len2 = ans.size();
    int len = max(len1, len2); // 取最大长度
    int temp_sum = 0;   // 每位数的和
    int r = 0;          // 进位
    vector<char> res;    // 结果

    for (int i = 0; i < len; i++)
    {
        // 每位数的和
        if (i < len1)  // temp里面还有数
            temp_sum += temp[i] - '0';
        if (i < len2)  // ans里面还有数
            temp_sum += ans[i] - '0';
        
        temp_sum += r;      // 加上进位
        r = temp_sum / 10;  // 更新进位 
        res.push_back(temp_sum % 10 + '0');
        temp_sum = 0;  // 重置为0用于下一个循环
    }

    if (r != 0) // 如果有进位
    {
        res.push_back(r + '0');
    }

    return res;
}

// 高精度乘法
vector<char> multiply(vector<char> temp, int n)
{
    int len = temp.size();
    int temp_sum = 0;
    int r = 0;
    vector<char> res;

    for (int i = 0; i < len; i++)
    {
        temp_sum = (temp[i] - '0') * n + r;
        r = temp_sum / 10;
        res.push_back(temp_sum % 10 + '0');
    }

    while (r != 0)  // 如果有进位
    {
        res.push_back(r % 10 + '0');
        r /= 10;
    }

    return res;
}

int main()
{
    int n;
    cin >> n;

    vector<char> temp = {'1'};  // 阶乘初始值为1
    vector<char> ans = {'0'};   // 累加和初始为0

    for (int i = 1; i <= n; i++)
    {
        temp = multiply(temp, i);
        ans = sum(temp, ans);
    }

    // 输出结果,倒序输出
    for (int i = ans.size() - 1; i >= 0; i--)
    {
        cout << ans[i];
    }

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值