题目链接:ZZULIOJ
1089: 阶乘的最高位
时间限制: 1 Sec 内存限制: 128 MB
提交: 8968 解决: 1526
[提交] [状态] [讨论版] [命题人:admin]
题目描述
输入一个正整数n。输出n!的最高位上的数字。
输入
输入一个正整数n(n不超过1000)。
输出
输出n!的最高位上的数字。
样例输入 Copy
1000
样例输出 Copy
4
提示
注意double类型溢出问题。
思路:
方法一:如果你使用的编程语言有大整形类型(如Python)的话,你可以直接求出N!,然后在求最高位的数字。
方法二:如果你使用的编程语言没有大整形类型的话,你可以使用这种方法,求N!,从N = 1开始,一直到N = n,中间结果如果有大于100000000的话,就只要前8位数,也就是循环除以10,直到N!的结果小于100000000,最后在求得最高位的数字。
注意:
网上有很多博客上的方法是错误的,大多是在求N!的过程中,如果中间结果大于10 ,就只保留最高位的数字,然后用此中间结果继续运算。我觉得这种方法是有问题的,如图:
虽然用前8位比用只用最高位的结果精确点,但是还是存在误差的,只是没有在1000这个范围内显示出来,如果有可能的话最好使用方法一,或者找到更合理的方法。
更:
经过提醒才想到其实是可以使用double存储中间结果的,当时当中间结果大于某一个数的时候我们需要对中间结果缩小,让其除以10,100,1000或者更大的数,其目的是为了保证结果不会溢出double的表示范围,对最终结果取最高位有效数字就是我们想要的结果。
我作这道题的时候,学校oj上给的数据有误,很随便就过了,所以我又找个其他的oj上的这道题,提交了一下,都过了,下面给出其他oj链接:阶乘最高位 - 题库 - RQNOJ
代码:
C++
#include <bits/stdc++.h>
using namespace std;
int main()
{
long long n, ans = 1;
cin >> n;
for(int i = 1; i <= n; i++)
{
ans *= i;
while(ans >= 100000000)
ans /= 10;
}
while(ans > 10)
ans /= 10;
cout << ans << endl;
return 0;
}
C
#include<stdio.h>
int main()
{
long long ans = 1;
int n, i;
scanf("%d", &n);
for(i = 2; i <= n; i++)
{
ans *= i;
while(ans >= 100000000)
ans /= 10;
}
while(ans >= 10)
ans /= 10;
printf("%lld\n", ans);
return 0;
}