标签:style 16px turn 质数 font div sam put 题目
一、题目
Description
求1*2*3*…*N所得数末尾有多少个0?(1<=N<=unsigned INT_MAX)
Input
有多组数据,第一行一个正整数t(t<100)表示输入数据组数,接下来有t组输入数据,每组数据占1行,输入为一个整数。
Output
输出一个整数,表示末尾有多少个0,对于每组输入,输出一行。
Sample Input
1
100
Sample Output
24
二、 解题分析:
题目是求 N的阶乘,但如果要利用 for 循环求的阶乘的结果 sum,然后再去 模10计数,但是N的阶乘肯定会溢出
所以在 for循环 内一个一个的求取 <方法1>,但是此题会超时,这就很尴尬!
所以找一下规律<方法2>:很容易知道能产生 0 的情况是 2*5 = 10 ,所以对 N 进行质数因子分解
N=2^x * 3^y * 5^z...,由于10 = 2*5,所以末尾0的个数只和x与z有关,每一对2和5相乘可以得到一个10,于是末尾0的个数 count = min (x,z)
因为整除 2 的数 个位情况是 0、 2、 4 、6、 8,但是整除 5 的数的个位情况是:0、5
所以x的值一定会比z的大,找0的个数实际上是找 N!分解 5 的 个数 。
公式: z = N/5 + N/5^2 + N/5^3+...+N/5^k
关于这个公式的理解:我们要找的是 分解 5 的个数,即找这个数之前(包括自己)出现了几次能够整除5的数,
比如 N = 15 ,则1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 所以 count = 15/5=3
但是:当N是 5的阶乘 (5^z)时的倍数是还会增加,
比如 N = 25, 则 1 2 3 4 5 6 7 ......10......15......20........25..... 此时有 25 / 5 = 5个,注意:25也是(5^2)的倍数,再加1
所以。。。。。。。。。。。。
<方法1>
#include<iostream> #include<stdio.h> using namespace std; int main() { int t; scanf("%d",&t); while(t--) { int n; scanf("%d",&n); int sum = 1; int count = 0; for(int i = 1;i <= n; i++) { sum *= i; while(sum % 10 == 0) { count++; sum /= 10; } sum %= 10; } printf("%d\n",count); } return 0; }
<方法2>
#include<iostream> #include<stdio.h> using namespace std; int main() { int t; scanf("%d",&t); while(t--) { int count = 0; int n; scanf("%d",&n); while(n) { count += n/5; n /= 5; } printf("%d\n",count); } return 0; }
标签:style 16px turn 质数 font div sam put 题目
原文地址:http://www.cnblogs.com/hhkobeww/p/7625872.html