试统计正整数n的阶乘n!的尾部连续零的个数。
输入样例
2015
输出
502
算法分析:
由于n的规模比较大,其尾数的个数也会非常多,所以在这里我们可以用一个数组来存储阶乘的的各位数字,a[0]存储个位,a[1]存储十位,依次类推。
(1)首先求出 n! 的总位数(取lg最后不要忘了+1)
总位数m = lg(2 * 3 * 4 * 5 * .... * n) +1
= lg2 + lg3 +lg4 + lg5 + ...lg n +1
(2)开两重循环模拟乘法(阶乘)
(a)然后设置循环进行累乘,将各位数值存入a数组中。i的结果依次为
2、3、4、5、6、......、n
(b) 设g为进位数, 各个数的乘积 t = a [ j ] * i + g,
(c)乘积t的个位数字存于本数组a [ j ] = t %10
乘积t的十位以上数字作为进位数g,即余数g = t /10
(d)开设一个while循环计算零的个数
代码
#include<iostream>
#include<cmath>
using namespace std;
const int N = 1e5 + 10;
int n;
int m;
double s;
int a[N];
int count = 1;
long g;
int main()
{
cin >> n;
for(int i = 2; i <= n; i++)
s += log10(i);
m=(int)s+1; //计算总位数
a[1]=1;g=0;
for(int i = 2; i <= n; i++)
{
for(int j=1; j<=m; j++)
{
long t=a[j]*i+g; //用第j位乘以下一个阶乘数字
a[j]=t%10; //a[J]只保留乘积的各位数字
g=t/10; //去掉个位数字后当作进位
}
}
while(a[count]==0)
count++;
printf("%d\n",count-1);
}
算法优化
从数学的思想考虑:
例如2015!= 1 * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 * 10 * … * 2014 * 2015
只有所有因子 2 和 5 相乘时,乘积才会出现一个零,又因为因子2的个数远多于因子5的个数,所有阶乘尾部0的个数由因子5的数量决定
问题就转换成 2015 ! 中由多少个因子5.
从上述式子中不难发现每五个数字会出现一个因子5
1 2 3 4 5 -----6 7 8 9 10 即形成了这样的表达形式A
{…5,…10,…15,…20,…2015} 共计2015/5个
以此类推
将A式子提取公因式形成B式
5*{1,2,3,4,5,6,7,8,9,10…}
进而整理成C式
5*{…5,…10,…15,…,20…} 共计2015/(5*5)
代码
#include<iostream>
using namespace std;
long long n;
int count;
long long t = 1;
int main()
{
cin>>n;
while(t <= n)
{
t = t * 5;
count = count + n / t;
}
cout<<count;
return 0;
}