东华oj-进阶题第23题-阶乘最后的非0位

在这里插入图片描述

23 阶乘最后的非0位

作者: XXX时间限制: 1S章节: 循环

问题描述 :

N的阶乘写作N!表示小于等于N的所有正整数的乘积。阶乘会很快的变大,如13!就必须用32位整数类型来存储,70!即使用浮点数也存不下了。你的任务是找到阶乘最后面的非零位。举个例子,5!=12345=120所以5!的最后面的非零位是2,7!=1234567=5040,所以最后面的非零位是4。
输入说明 :

一个不大于1000的整数N。 输出说明 :

共一行,输出N!最后面的非零位。 输入范例 : 7 输出范例 : 4

代码:

/*
	T23 阶乘最后的非零位 
*/ 

#include<stdio.h>
#include<string.h>
#define MAX_SIZE 35700 // 10000的阶乘有35660位 

int res[MAX_SIZE];// 存放大整数乘法的结果 
void bigNumMulti(int n);

int main() {
	int N = 0;
	int i = 0;
	
	scanf("%d", &N);
	memset(res, -1, sizeof(res));// 重置结果 
	
	for (i = 1; i <= N; i++) {
		bigNumMulti(i);
	} 
	
	i = MAX_SIZE;
	while (res[--i] == 0);// 跳过后面的0 
	printf("%d\n", res[i]);
	
	return 0;
} 

// 计算res表示的大整数与n的乘积
void bigNumMulti(int n) {// 15!开始就有问题了 
	int copyRes[MAX_SIZE] = {0};// 存放res的副本 
	int addArr[MAX_SIZE];// 存放计算乘法时中间的加数 
	int addCarry = 0, multiCarry = 0;// 加法的进位,乘法的进位
	int i = MAX_SIZE - 1, j = 0; 
	int digit = 0;// n的各个位数字 
	int multiTemp = 0;// 大整数与n的各个位相乘的中间结果 
	int addTemp = 0;// 加法的中间结果 
	int multiCount = 0;// 记录已经做了几次乘法 
	int nTemp = n; 
	
	if (res[MAX_SIZE - 1] != -1) {
		for (i = 0; i < MAX_SIZE; i++)// 更新副本(有结果的情况才需要更新) 
			copyRes[i] = res[i];	
		memset(addArr, -1, sizeof(addArr));// 将原结果清空			
	}
	else {// 初始情况,也就是n=1进来的时候 
		memset(copyRes, -1, sizeof(copyRes)); 
		copyRes[MAX_SIZE - 1] = 1;
		res[MAX_SIZE - 1] = 0;
	}
	memset(addArr, -1, sizeof(addArr)); 
	
	while (n) {// n的各个位与大整数的乘积 
		digit = n % 10;
		addCarry = 0, multiCarry = 0;// 重置进位
		 
		// 乘法原理:一个整数的各个位(设为a)与一个数字digit相乘的结果为 
		// a乘上digit加上上一个进位
		for (i = MAX_SIZE - 1; copyRes[i] != -1; i--) {
			multiTemp = copyRes[i] * digit + multiCarry; 
			addArr[i] = multiTemp % 10; 
			multiCarry = multiTemp / 10;// 更新进位 
		} 
		if (multiCarry > 0) {// 处理溢出的进位 
			addArr[i] = multiCarry;
		}
		
		// 加法原理:一个整数的各个位(设为a)与另一个整数的对应位(设为b)
		// 相加,结果为a加上b再加上上一个进位 
		for (i = MAX_SIZE - 1; addArr[i] != -1; i--) {
			if (multiCount == 0) {// 个位数,只做一次乘法的情况 
				res[i] = addArr[i];
			}
			else {// 做多次乘法的情况 
				if (res[i - multiCount] == -1)// 处理上一个加数越位的-1,为下一次加法做准备 
					res[i - multiCount] = 0;
				addTemp = res[i - multiCount] + addArr[i] + addCarry;
				res[i - multiCount] = addTemp % 10;
			}	
			addCarry = addTemp / 10;// 更新进位 
		}
		if (addCarry > 0) {// 处理溢出的进位,注意依然是i - multiCount 
			//错误写法!:res[i] = addCarry;这样就把结果的第2位覆盖了 
			res[i - multiCount] = addCarry;
		}
		
		memset(addArr, -1, sizeof(addArr));// 清空加数数组 
		multiCount++;// 乘法次数加1 
		n /= 10;
	}
	
}

用到了大整数的乘法

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值