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

该博客介绍了一种计算1到n阶乘之和的方法,利用高精度加法和乘法实现。代码示例展示了如何计算不超过50的整数阶乘之和,输入一个数n,输出其阶乘之和的高精度结果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接

题目大意

用高精度计算出 S = 1 ! + 2 ! + 3 ! + . . . . + n ! ( 1 < = n < = 50 ) S = 1! + 2! + 3! + .... + n! (1<=n<=50) S=1!+2!+3!+....+n!(1<=n<=50)。其中 ! 表示阶乘。

思路

高精度加法和乘法的使用

输入与输出

输入

3

输出

9

AC代码

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>	
#include<math.h>
#include<queue>

using namespace std;

int a[5005], b[5005], c[5005];

void mul(int *a,int c)
{
	int tmp = 0;
	for (int i = 1; i <= 1000; ++i)
	{
		a[i] = a[i] * c + tmp;
		tmp = a[i] / 10;
		a[i] %= 10;
	}
}

void pluss(int *a,int *c)
{
	int tmp = 0;
	for (int i = 1; i <= 1000; ++i)
	{
		c[i] += a[i] + tmp;
		tmp = c[i] / 10;
		c[i] %= 10;
	}
}

int main(int argc, char* argv[])
{
	int n;
	scanf("%d", &n);
	a[1] = 1;
	for (int i = 1; i <= n; ++i)
	{
		mul(a,i);//计算!a
		pluss(a, c);
	}
	int flag = 0;
	for (int i = 1000; i >= 1; --i)
	{
		if (c[i] != 0)flag = 1;
		if (flag)printf("%d", c[i]);
	}
	return 0;
}

<think>嗯,用户问的是P1009 [NOIP 1998 普及组] 阶乘之和的问题。首先我得回想一下这个题目的具体要求。题目应该是要求计算S = 1! + 2! + 3! + ... + n!,其中n是一个给定的正整数,对吧?不过可能具体数值范围需要确认,比如n的上限是多少,这会影响到如何处理大数的问题。 然后,用户可能是在准备NOIP或者类似的竞赛题目,所以需要给出算法思路和实现方法。因为阶乘增长得非常快,当n比较大的时候,比如n=20,20!已经是一个很大的数,超过普通数据类型的范围,比如64位整型可能都不够用。因此,这道题的关键点应该在于如何处理大数计算,也就是高精度运算。 接下来,我需要考虑如何实现高精度的阶乘和求和。通常,高精度计算可以用数组或者字符串来模拟每一位数字,进行逐位的乘法和加法操作。比如,用数组的每一位存储数字的一位,低位在前或者高位在前都可能,但通常低位在前更容易处理进位。 首先,阶乘的计算。比如,计算i!的时候,可以用一个数组或列表来保存当前的结果,然后每次乘以i,并处理进位。例如,初始时1!是1,数组是[1]。计算2!的时候,就是1*2=2,数组变成[2]。3!是2*3=6,数组是[6]。到4!的时候,6*4=24,这时候数组可能需要变成[4,2],因为个位是4,十位是2。这样每一位乘以当前的数,然后处理进位。 然后,阶乘之和的问题,需要将每个i!的结果相加。这时候需要另一个数组来保存总和,每次将当前的i!加到总和数组中。高精度加法需要考虑两个数的位数,逐位相加,进位处理。例如,总和数组初始为空,第一次加1!,得到[1]。第二次加2!,即1+2=3,总和是3。第三次加6,总和是9,依此类推,直到加到n!。 这时候,我需要考虑如何将这两个过程结合起来。比如,对于每个i从1到n,先计算i的阶乘,然后将其加到总和里。具体步骤可能如下: 1. 初始化总和数组sum为0。 2. 初始化阶乘数组factorial为1(对应1!)。 3. 对于i从1到n: a. 将factorial加到sum中。 b. 计算下一个阶乘,即factorial乘以(i+1),注意i的循环可能需要调整,比如如果是i从1到n,那么下一个阶乘是乘以i+1?或者初始是1!,然后i从2到n,乘以i。这点需要仔细考虑循环结构。 4. 最后输出sum数组的值。 不过具体实现时,阶乘的计算应该在每次循环中乘以当前的i。例如,初始时factorial是1(1!)。当i=1时,加到sum里,然后计算i=2的时候,factorial *=2得到2!,再加到sum里。这样循环到i=n。 因此,正确的流程应该是: - sum初始化为0。 - factorial初始化为1。 - 对于i从1到n: - sum += factorial - factorial *= (i+1) ? 这里可能有问题,因为当i=1的时候,下一个阶乘是2! =1! *2,所以应该是factorial *=i+1?或者更准确地说,当i从1到n时,每次循环处理i的阶乘,加到sum之后,计算下一个阶乘应该是乘以i+1。或者更简单的是,在循环内部,先加到sum,然后更新factorial为factorial * (i+1)? 或者,另一种方式是,factorial初始化为1(即1!),然后循环从i=1到n,每次将factorial加到sum,然后计算下一个阶乘,即factorial *= (i+1)。例如: i=1时,factorial是1!,加到sum。然后计算factorial *=2得到2!,i=2时加到sum,接着factorial *=3得到3!,直到i=n。 这样循环的次数是n次,每次处理i!。例如,当n=3时,i=1处理1!,i=2处理2!,i=3处理3!。这似乎没问题。不过这里i的循环可能应该从1到n,而阶乘的更新是乘以(i+1)吗?或者应该循环中的i对应的是当前的阶乘数? 或者,另一种思路是,循环i从1到n,每次计算i的阶乘,然后加到sum。这时候,计算i!可以通过从1乘到i,但是这样每次都要重新计算阶乘,效率不高。所以更高效的做法是,利用之前的阶乘结果,乘以当前的i得到新的阶乘。例如: 初始factorial为1(即1!) sum += factorial (i=1) 然后i=2时,factorial *=2 →2!,sum +=2! i=3时,factorial *=3 →6=3!,sum +=3!,依此类推。 这样,循环变量i从1到n,每次循环时: sum += factorial 然后 factorial *= (i+1) ? 或者,这样是否正确呢?例如,当i=1时,计算的是1!,然后下一个阶乘是乘以2得到2!。所以,应该在循环中,i从1到n,每次处理i的阶乘,而阶乘的计算是通过前一个阶乘乘以当前的i? 或者,可能我之前的方法有问题。正确的应该是,初始factorial为1(1!),sum加上之后,然后i从2到n,每次factorial *=i,sum加上factorial。例如,当n=3时: 初始化sum=0,factorial=1。 i=1: sum += factorial → sum=1 然后,因为接下来要计算2!,需要将factorial乘以2 → factorial=2 i=2: sum +=2 → sum=3 factorial *=3 →6 i=3: sum +=6 → sum=9 循环结束。所以,这样处理的话,循环次数是n次,i从1到n,每次处理i!,然后乘以i+1?这似乎有问题,因为当i=1时,下一个是i+1=2,所以乘以2得到2!。然后i=2的时候,乘以3得到3!,此时i的循环次数应该是n次,对吗?这可能和循环变量的设计有关。 或者,可能更好的方式是,循环变量i从1到n,每次循环中,factorial *=i,这样初始的factorial为1,当i=1时,factorial *=1 →1!,加到sum。然后i=2,factorial *=2 →2!,加到sum。这样循环i从1到n,每次循环中,factorial *=i,然后加到sum。但这样的话,初始的factorial应该是1,然后在循环中首先乘以i,得到i!。例如: sum =0 factorial=1 for i in 1..n: factorial *=i # 此时factorial是i! sum +=factorial 这样是否正确?比如,当i=1时,factorial=1*1=1!,加到sum。i=2时,factorial=1*1*2=2!,加到sum。i=3时,factorial=1*1*2*3=3!,依此类推。是的,这样是正确的。但这样每次循环中,factorial *=i,初始为1,这样得到的是i!。那这样的话,i从1到n循环,就能得到1!到n!的和。这可能更直接。 所以,问题的核心在于如何高效计算阶乘并累加,同时处理大数问题。因为n可能较大,比如题目中的测试点可能有n=50或者更大的情况,这时候必须使用高精度计算。 那现在,如何用高精度实现阶乘和加法? 首先,高精度的阶乘计算:可以用一个数组或列表,每一位存储一个数字,比如低位在前,这样进位处理方便。例如,数字1234可以存储为[4,3,2,1],这样当乘以一个数时,可以逐位相乘并处理进位。 例如,计算3!: 1. 初始为1 → [1] 2. 乘以2 → [2] 3. 乘以3 → [6] 所以3!是6,存储为[6] 计算4!: 6乘以4 → 每位处理:6*4=24 → 4进位2 → 所以结果是[4,2] → 即24,但存储是低位在前,所以表示为[4,2],即24。 然后,计算阶乘之和的时候,需要将每个阶乘的结果相加。比如sum初始为空,或为0,然后依次加上每个阶乘的高精度数。 高精度加法需要处理两个数的位数,以及进位。例如,当前sum是[3](即3),要加上[6](即6),得到[9]。当sum是[9](9),加上[24](存储为[4,2]),那么需要将每一位相加,0+4=4,9+2=11,所以结果是[4,1],进位1,所以最终变为[4,1,1],即 114? 不对,可能哪里弄错了。 或者,可能我的存储顺序有问题。例如,sum是[9](即9),而加上[4,2](即24),则sum的每一位是9在个位,而另一个数是4在个位,2在十位。相加的话,个位9+4=13,记录3,进位1。十位0+2+1=3。所以结果是[3,3,1]吗?或者存储顺序的问题? 或者,正确的加法方式应该是这样的:例如,sum是[9],即数字9,另一个数是[4,2],即24。加法时,个位相加9+4=13,所以个位是3,进位1。十位0+2+1=3,所以十位是3。所以结果是[3,3],即33,也就是9+24=33。存储顺序是低位在前,所以33的表示是[3,3]。 这样,加法的时候,需要将sum和当前阶乘的数组进行逐位相加,并处理进位。 那具体的实现步骤可能如下: 1. 初始化sum数组为空,或者初始为0(即[0])。 2. 初始化factorial数组为[1]。 3. 对于i从1到n: a. 将factorial数组加到sum数组中,使用高精度加法。 b. 计算factorial数组乘以(i+1)得到下一个阶乘?或者,步骤a之后,计算factorial *= (i+1)?或者,这里的i的处理方式可能有误,需要重新考虑。 或者,根据之前的分析,正确的阶乘计算方式是在每次循环中,factorial *=i。例如: 初始化factorial为[1] sum初始化为[0] 然后,循环i从1到n: factorial = factorial * i → 这样,第一次i=1时,factorial是1*1=1,即1!。加到sum,sum变为1。第二次i=2,factorial是1*2=2 →2!,加到sum得到3。第三次i=3,factorial是2*3=6→3!,sum变成9,依此类推。 哦,原来如此。这样,每次循环中,i的当前值被乘到factorial中,得到i!。例如: i=1时,factorial *=1 →1!,sum +=1! i=2时,factorial *=2 →2!,sum +=2! i=3时,factorial *=3 →3!,sum +=3! 这样,循环n次,i从1到n,每次得到i!,然后加到sum中。这样是正确的。 那现在,如何实现高精度乘法和加法? 首先,高精度乘法:一个高精度数(数组)乘以一个整数i。例如,数组是[4,2](表示24),乘以i=5,得到120。具体步骤是: 每一位数字乘以i,并处理进位。例如: 初始数组是[4,2],i=5。 个位4*5=20,保留0,进位2。 十位2*5=10,加上进位2得到12,保留2,进位1。 然后,进位1需要处理,所以结果数组变成[0,2,1],即0在个位,2在十位,1在百位,即120。 存储顺序是低位在前,所以数组是[0,2,1]。 所以,高精度乘法的步骤是: 1. 初始化进位为0。 2. 遍历高精度数的每一位: a. 当前位乘以i,加上进位。 b. 新的当前位的值为总和对10取余。 c. 新的进位为总和对10取整。 3. 处理剩余的进位,如果大于0,需要添加到高位。 然后,高精度加法:将两个高精度数相加,例如sum数组和factorial数组相加。假设sum是[3](3),factorial是[0,2,1](120),那么相加结果是123,存储为[3,2,1]。 具体步骤是: 1. 初始化进位为0。 2. 遍历两个数组的每一位,直到处理完较长的数组。 3. 每一位的和等于sum的当前位(如果存在)加上factorial的当前位(如果存在)加上进位。 4. 新的当前位为和%10,进位为和//10。 5. 最后处理剩下的进位。 所以,现在的问题是,如何用代码实现这些步骤,或者给用户提供算法的步骤,让他们自己编写代码。 对于用户的问题,他们可能需要一个算法思路,以及如何处理高精度运算。此外,可能需要给出一个代码示例,比如用C++或Python实现,但用户可能更倾向于Python,因为处理大数相对容易,但题目可能要求用C++。不过原题是NOIP普及组的题目,所以可能需要用Pascal或者C++。不过用户可能只是想了解思路。 所以,在回答中,应该分步骤说明: 1. 题目分析:计算阶乘之和,但n较大时,数值超过普通数据类型,需用高精度。 2. 算法思路: a. 高精度计算阶乘:用数组存储每一位,每次乘以i,处理进位。 b. 高精度加法:将每个阶乘结果累加到总和中。 3. 具体步骤: a. 初始化阶乘数组和总和数组。 b. 循环i从1到n: i. 计算当前阶乘(乘以i)。 ii. 将当前阶乘加到总和中。 c. 输出总和数组。 4. 实现细节: a. 高精度乘法的实现。 b. 高精度加法的实现。 c. 数组的存储方式(低位在前)。 可能的陷阱包括: - 阶乘乘法的顺序,例如,在循环中必须正确更新阶乘数组。 - 处理进位的时候,特别是乘法和加法中的进位可能不止一位。 - 数组的索引管理,低位在前的高精度处理。 例如,当n=3时,总和应该是1!+2!+3!=1+2+6=9。当n=10时,总和是4037913,但具体需要验证。 现在,考虑如何用Python实现高精度,虽然Python本身支持大整数,但为了教学目的,可能需要手动模拟这个过程,以展示高精度处理的步骤。 或者,用户可能需要知道如何处理,而不管具体语言。所以,给出步骤即可。 比如,对于阶乘计算: 初始化fact为[1](表示1)。 sum为[0]。 然后,对于每个i从1到n: fact = fact * i → 高精度乘法。 sum = sum + fact → 高精度加法。 然后,输出sum的数组,按逆序输出。 例如,n=3时: i=1: fact = [1] *1 → [1] sum = [0] + [1] → [1] i=2: fact = [1] *2 → 2 → [2] sum = [1] + [2] →3 → [3] i=3: fact = [2] *3 →6 → [6] sum = [3] + [6] →9 → [9] 所以,结果数组是[9],输出9。 当n=10时,正确的结果是4037913,那么高精度计算会得到这个结果。 在代码实现中,可以用数组来存储这些数字。例如,Python中可以用列表,每个元素是数字的一位,低位在前。 然后,实现乘法函数和加法函数。 例如,乘法函数: def multiply(num, i): carry =0 result = [] for digit in num: product = digit * i + carry result.append(product %10) carry = product //10 while carry >0: result.append(carry%10) carry = carry //10 return result 加法函数: def add(a, b): result = [] carry =0 max_len = max(len(a), len(b)) for i in range(max_len): digit_a = a[i] if i < len(a) else 0 digit_b = b[i] if i < len(b) else 0 total = digit_a + digit_b + carry result.append(total%10) carry = total //10 if carry >0: result.append(carry) return result 然后,主程序: n = int(input()) fact = [1] sum_total = [0] for i in range(1, n+1): # 计算当前阶乘:fact = fact * i fact = multiply(fact, i) # 将阶乘加到总和 sum_total = add(sum_total, fact) # 输出总和,逆序输出 print(''.join(map(str, reversed(sum_total)))) 这样,应该可以得到正确的结果。例如,n=3,输出9;n=10,输出4037913。 但需要测试一下代码是否有错误。例如,乘法是否正确,加法是否正确。 比如,测试阶乘计算: i=1: fact初始为[1] → multiply([1],1) → [1] i=2: multiply([1],2) → [2] i=3: multiply([2],3) → 6 → [6] i=4: multiply([6],4) → 24 → [4,2] 是的,正确。 加法测试: sum初始为[0],第一次加[1] → [1] 第二次加[2] → [3] 第三次加[6] → [9] 正确。 当i=4时,fact是[4,2](24),sum是9 →9+24=33 → [3,3] 所以,sum_total在四次循环后是1+2+6+24=33,即当n=4时,输出33。 这正确,因为1!+2!+3!+4! =1+2+6+24=33. 所以,代码应该正确。 综上,用户的问题需要介绍这个题目的解法,重点在于高精度处理阶乘和求和。因此,回答的结构应该包括题目分析、算法思路、具体实现步骤,以及可能的代码示例(如果需要的话)。同时,根据用户的要求,使用中文回答,结构清晰,步骤详细。</think>### P1009 [NOIP 1998 普及组] 阶乘之和 解答 #### 题目分析 要求计算 $S = 1! + 2! + 3! + \dots + n!$($n \leq 50$)。 **核心难点**:阶乘增长极快(如 $20! \approx 2.43 \times 10^{18}$),远超普通整数范围,需用**高精度运算**处理。 --- #### 算法思路 1. **高精度乘法**:逐位计算阶乘,用数组存储每一位(低位在前,便于处理进位)。 - 示例:计算 $4!$ $$1 \xrightarrow{\times 2} 2 \xrightarrow{\times 3} 6 \xrightarrow{\times 4} 24 \quad \text{(存储为 } [4,2]\text{)}$$ 2. **高精度加法**:将每个阶乘结果累加到总和中。 - 示例:$9 + 24 = 33$ $$[9] + [4,2] \rightarrow [3,3] \quad \text{(即 } 33\text{)}$$ --- #### 具体步骤 1. **初始化**: - 阶乘数组 `fact = [1]`(表示 $1!$) - 总和数组 `sum_total = [0]` 2. **循环计算**($i$ 从 $1$ 到 $n$): - **计算当前阶乘**:`fact = fact * i`(高精度乘法) - **累加到总和**:`sum_total = sum_total + fact`(高精度加法) 3. **输出结果**:将 `sum_total` 逆序输出(高位在前)。 --- #### 代码实现(Python 模拟高精度) ```python def multiply(num, i): carry = 0 result = [] for digit in num: product = digit * i + carry result.append(product % 10) carry = product // 10 while carry > 0: result.append(carry % 10) carry = carry // 10 return result def add(a, b): result = [] carry = 0 max_len = max(len(a), len(b)) for i in range(max_len): digit_a = a[i] if i < len(a) else 0 digit_b = b[i] if i < len(b) else 0 total = digit_a + digit_b + carry result.append(total % 10) carry = total // 10 if carry > 0: result.append(carry) return result n = int(input()) fact = [1] sum_total = [0] for i in range(1, n + 1): fact = multiply(fact, i) sum_total = add(sum_total, fact) print(''.join(map(str, reversed(sum_total)))) ``` --- #### 示例验证 - **输入**:`n = 3` **输出**:`9`($1! + 2! + 3! = 1 + 2 + 6 = 9$) - **输入**:`n = 10` **输出**:`4037913` --- #### 关键点总结 1. **高精度乘法**:逐位计算并处理进位。 2. **高精度加法**:对齐位数后逐位相加。 3. **存储顺序**:低位在前简化进位逻辑。 通过分步模拟高精度运算,可有效解决大数阶乘求和问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值