题面
题目:
运用高精度计算出 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;
}
反思
相较于上次高精度乘法,简化了 确定位数、去除首导零 的步骤,精简代码长度,同时实现多数累乘的操作。
268

被折叠的 条评论
为什么被折叠?



