阶乘之和(高精度)

题面

题目:

运用高精度计算出 S=1!+2!+3!+...+n!

输入格式:

正整数n

输出格式:

正整数S,表示从1到n的阶乘之和


思路

运用高精度乘与高精度和知识,搭配循环解题


步骤

1、定义高精度累乘

每输入一个数,都会和先前的计算结果相乘,符合阶乘的本质——累乘

vector<long long> numbers = { 1 };//定义数组并赋初始值为1
void multiply(long long a)
{
	for_each(numbers.begin(), numbers.end(), [a](long long n)mutable {n = n * a; });
	//每个元素都乘以输入数据a

    int i = 0;
	while (i < numbers.size())//逐次进位,直至最高位
	{
		if (i == numbers.size() - 1)//到最高位了,接下来判断是否需要进位
		{
			if (numbers.back() < 10)
			{
				break;
			}
            //不需要进位,直接跳出循环

			else
			{
				numbers.push_back(0);
			}
            //需要进位,在数组末尾加一个元素0,并在接下来代码中执行进位操作

		}
		numbers[i + 1] += numbers[i] / 10;
		numbers[i] = numbers[i] % 10;
		i++;
        //常规进位操作(开头为低位,末尾为高位)
	}
}

2、定义高精度累加

与累乘类似,定义初始数组,逐次与输入数据累加

vector<long long> sum = { 0 };
void Sum()
{
	if (sum.size() > numbers.size())
	{
		for (size_t i = 0; i < numbers.size(); i++)
		{
			sum[i] += numbers[i];
		}
	}
	else
	{
		for (size_t i = 0; i < sum.size(); i++)
		{
			numbers[i] += sum[i];
		}
		sum = numbers;
	}
    //先比较被加数与加数位数高低,将位低者加在位高者上,以免出现位低者高位元素未赋初值情况


	int i = 0;
	while (i < sum.size())
	{
		if (i == sum.size() - 1)
		{
			if (sum.back() < 10)
			{
				break;
			}
			else
			{
				sum.push_back(0);
			}
		}
		sum[i + 1] += sum[i] / 10;
		sum[i] = sum[i] % 10;
		i++;
	}
    //老生常谈进位

}

3、主函数

长度虽短但却暗藏玄机,输出部分尤其注意

int main()
{
	long long n;
	cin >> n;
	for (auto i = 1; i <= n; i++)
    //auto是自动判断变量型,这里判断为long long,但是懒得写了:)

	{
		for (auto j = 1; j <= i; j++)
		{
			multiply(j);
		}
		Sum();
		numbers = { 1 };
        //每次累加后将累乘数组初始化,以便下次累乘与累加

	}

	for (size_t j = sum.size() ; j > 0; j--)
	{
		cout << sum[j - 1];
	}
    /*
    size_t是sum.size()的类型,即无符号整型,若减为负,会发生环绕,变为正数最大值
    即2^32-1或2^64-1。故在输出循环中不能让j减为负值。以上写法正确,读者也可以尝试
    其他正确写法。
    */

	return 0;
}


完整代码与注释

#include<iostream>
#include<vector>
#include<algorithm>
#include<cmath>
#include<sstream>
using namespace std;

vector<long long> numbers = { 1 };//定义数组并赋初始值为1
vector<long long> sum = { 0 };

void multiply(long long a)
{
	for_each(numbers.begin(), numbers.end(), [a](long long& n)mutable {n = n * a; });
	//每个元素都乘以输入数据a

    int i = 0;
	while (i < numbers.size())//逐次进位,直至最高位
	{
		if (i == numbers.size() - 1)//到最高位了,接下来判断是否需要进位
		{
			if (numbers.back() < 10)
			{
				break;
			}
            //不需要进位,直接跳出循环

			else
			{
				numbers.push_back(0);
			}
            //需要进位,在数组末尾加一个元素0,并在接下来代码中执行进位操作

		}
		numbers[i + 1] += numbers[i] / 10;
		numbers[i] = numbers[i] % 10;
		i++;
        //常规进位操作(开头为低位,末尾为高位)
	}
}


void Sum()
{
	if (sum.size() > numbers.size())
	{
		for (size_t i = 0; i < numbers.size(); i++)
		{
			sum[i] += numbers[i];
		}
	}
	else
	{
		for (size_t i = 0; i < sum.size(); i++)
		{
			numbers[i] += sum[i];
		}
		sum = numbers;
	}
    //先比较被加数与加数位数高低,将位低者加在位高者上,以免出现位低者高位元素未赋初值情况


	int i = 0;
	while (i < sum.size())
	{
		if (i == sum.size() - 1)
		{
			if (sum.back() < 10)
			{
				break;
			}
			else
			{
				sum.push_back(0);
			}
		}
		sum[i + 1] += sum[i] / 10;
		sum[i] = sum[i] % 10;
		i++;
	}
    //老生常谈进位

}


int main()
{
	long long n;
	cin >> n;
	for (auto i = 1; i <= n; i++)
    //auto是自动判断变量型,这里判断为long long,但是懒得写了:)

	{
		for (auto j = 1; j <= i; j++)
		{
			multiply(j);
		}
		Sum();
		numbers = { 1 };
        //每次累加后将累乘数组初始化,以便下次累乘与累加

	}

	for (size_t j = sum.size() ; j > 0; j--)
	{
		cout << sum[j - 1];
	}
    /*
    size_t是sum.size()的类型,即无符号整型,若减为负,会发生环绕,变为正数最大值
    即2^32-1或2^64-1。故在输出循环中不能让j减为负值。以上写法正确,读者也可以尝试
    其他正确写法。
    */

	return 0;
}


反思

相较于上次高精度乘法,简化了 确定位数、去除首导零 的步骤,精简代码长度,同时实现多数累乘的操作。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值