阶乘问题
时间限制: 1 Sec 内存限制: 128 MB提交: 45 解决: 39
[ 提交][ 状态][ 讨论版]
题目描述
也许你早就知道阶乘的含义,N阶乘是由1到N相乘而产生,如:
12! = 1 x 2 x 3 x 4 x 5 x 6 x 7 x 8 x 9 x 10 x 11 x 12 = 479,001,600
12的阶乘最右边的非零位为6。
写一个程序,计算N(1<=N<=50,000,000)阶乘的最右边的非零位的值。
注意:10,000,000!有2499999个零。
12! = 1 x 2 x 3 x 4 x 5 x 6 x 7 x 8 x 9 x 10 x 11 x 12 = 479,001,600
12的阶乘最右边的非零位为6。
写一个程序,计算N(1<=N<=50,000,000)阶乘的最右边的非零位的值。
注意:10,000,000!有2499999个零。
输入
仅一行包含一个正整数N。
输出
单独一行包含一个整数表示最右边的非零位的值。
样例输入
12
样例输出
6
比赛时没想出好方法,直接遇到10取余,感觉每次乘积的结果取最低位就行了,结果因为数据水过了。
其实直接遇到10取余这种方法不仅慢,而且答案是错误的!(自己跑JAVA大数验证出来了。。)
举个栗子
本来当前数是 25 ,那么当他 * 4,之后变成了100,那么最右边不为0的数是1;
但是由于我们取模,变成了5 * 4 = 20,最右边变成了 2!
为了避免这种情况,我们遇到5就往下除,因为5的倍数出现的次数是一定比2的倍数要少。
然后根据除5的次数,去除2。
这样我们就不会遇到相乘得到10的倍数然后出现歧义的情况了,因为当前的积不会是10的倍数。
这里是问石油聚聚要来的代码,感谢。
#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
#include <cstdlib>
#include <stack>
#include <cstring>
#include <string>
#include <queue>
#include <set>
#define maxn 300000 + 10
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
int solve(int n){
int cnt = 0,sum = 1;
for(int i = 2; i <= n; i++) {
if(i % 5 == 0) {
int temp = i;
while(temp % 5 == 0) {
temp /= 5;
if(temp % 2 == 0)
temp /= 2;
else cnt ++;
}
sum = (sum * temp) % 10;
} else {
int temp = i;
while(cnt > 0 && temp % 2 == 0) {
temp /= 2;
cnt --;
}
sum = (sum * temp) % 10;
}
}
while(cnt > 0){
cnt--;
sum/=2;
}
return sum;
}
int main(){
int n;
while(scanf("%d",&n)!=EOF){
printf("%d\n",solve(n));
}
return 0;
}