不要用循环到202320232023求阶乘,数值太大,会超时。
找规律:
1!=1;2!=2;3!= 6;4!=24;5!=120(1个0);6!=720;7!=5040;8!=40320;9!=362880;
10!=3628800(2个0);11!=39916800;12!=479001600;13!=6,227,020,800;14!=87178291200;15!=1,307,674,368,000(3个0)
1!到9!的值较小且末尾没有很多个零,从10!起得到的阶乘值会有多个末尾0,因为每个阶乘相乘过程中会有多个2、5因子(可以理解为2、5的倍数)相乘得到10,即在末尾增0。
找出那个n0,即n0!末尾有9个0,则在n>n0之后的阶乘对S的末尾9位无影响。
可以认为:阶乘的末尾零的数量取决于因子 5 的数量,因为因子 2 的数量总是超过因子 5 的数量。注意这里的因子5,是每多一个5,5,25(5*5),125(5*25)
由公式可知10!起有2个0,15!起有3个0,类推得20!为4个0,25!为6个0,30!有7个0,35!有8个0,40!有9个0,45!起有10个0
则只计算1!到39!即可
代码:
#include <iostream>
using namespace std;
int main()
{
// 请在此输入您的代码
long long S=0;
for(int i=1;i<40;i++)
{
long long n=1;
for(int j=1;j<=i;j++)
{
n*=j;
n%=1000000000;//注意这里,一定要对每个n取余避免溢出
}
S+=n;
}
cout<<S%1000000000;
return 0;
}
注意:
首先,阶乘的值增长非常快:
- 10!=3628800
- 20!≈2.43×
- 30!≈2.65×
- 39!≈6.24×
这样大的数字对于计算机中的标准数据类型是很难处理的。如果你使用例如 long long
(在大多数编译器中是 64 位),它的最大值大约是 1.84×。当计算到 20!或更大的 n!时,就可能会很轻易超出
long long
能表示的范围。
如果没有 n %= 1000000000
,在 n *= j
这一行,当 n
增大到超过 long long
的范围时,会发生整数溢出。溢出后得到的值将是不可预测的,通常是在该类型能够表达的最大值周围“绕回”到负数或小数,这导致后续的结果也是错误的。
通过在每次计算后取模,保持 n在 0 到 999999999的范围内,确保每次的计算结果都是有效和准确的。这样能有效避免整数溢出,同时,也能保持程序在整次计算过程中的稳定性。
若其中任何一个 n 由于溢出导致了错误的值,那么 S
将会反映这种错误,最终导致输出结果也是错误的。