【题目链接】

ybt 2033:【例4.19】阶乘之和

【题目考点】

1. 同余定理

根据同余定理,有:
( a ∗ b ) % m = ( a % m ∗ b % m ) % m (a*b)\%m = (a\%m * b\%m)\%m (ab)%m=(a%mb%m)%m
( a + b ) % m = ( a % m + b % m ) % m (a+b)\%m = (a\%m + b\%m)\%m (a+b)%m=(a%m+b%m)%m

2. 循环嵌套
3. 阶乘

n的阶乘为 n ! = 1 ∗ 2 ∗ . . . ∗ n n!=1*2*...*n n!=12...n
实现函数如下:

int fact(int n)
{
	int s = 1;
	for(int i = 1; i <= n; ++i)
		s *= i;
	return s;
}

【解题思路】

  • 一个直接的思路是:求出每个数的阶乘,加和,而后对M取模(设M的值为1000000),就可以得到结果的末6位。但阶乘的结果很大,会超出int以及long long类型可以表示的数字范围,所以必须一边计算一边取模。
    a n s = 1 ! + 2 ! + . . . + n ! ans = 1!+2!+...+n! ans=1!+2!+...+n!
    根据同余定理,有:
    a n s % M = ( 1 ! % M + 2 ! % M + . . . + n ! % M ) % M ans\%M = (1!\%M+2!\%M+...+n!\%M)\%M ans%M=(1!%M+2!%M+...+n!%M)%M
    n ! % M = ( n % M ∗ ( n − 1 ) ! % M ) % M n!\%M = (n\%M*(n-1)!\%M)\%M n!%M=(n%M(n1)!%M)%M
    可以先求每个阶乘模M的值,然后将这些结果加起来,一边加一边对M取模,即可。
  • 如果分别对每个数值求阶乘,需要做n次阶乘,每次阶乘的复杂度是 O ( n ) O(n) O(n),总体复杂度是 O ( n 2 ) O(n^2) O(n2),而本问题n达到 1 0 6 10^6 106 O ( n 2 ) O(n^2) O(n2)会超时。
  • 考虑到当 n ≤ M n\le M nM时: n ! % M = ( n ∗ ( n − 1 ) ! % M ) % M n!\%M = (n*(n-1)!\%M)\%M n!%M=(n(n1)!%M)%M,我们可以借助上一次的阶乘结果 ( n − 1 ) ! % M (n-1)!\%M (n1)!%M,乘上数字n再对M取模,即可得到 n ! % M n!\%M n!%M。这样求每个阶乘的复杂度是 O ( 1 ) O(1) O(1),总体复杂度是 O ( n ) O(n) O(n),可以通过。

【题解代码】

解法1:
#include<bits/stdc++.h>
using namespace	std;
#define M 1000000 //设置常量,下面M就是1000000
int	main()
{
	int n, num = 1, sum = 0;//num:阶乘%M sum:阶乘和%M 
	cin >> n;
	for(int i = 1; i <= n; ++i)
	{
		num = num * i % M;
		sum = (sum + num) % M;
	}
	cout << sum;
	return 0;
}
Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐