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;
}
}
用到了大整数的乘法