洛谷P2388 阶乘之乘

题目背景

不告诉你……

题目描述

求出1!*2!*3!*4!*……*n!的末尾有几个零

输入输出格式

输入格式:

n(n<=10^8)

输出格式:

有几个零

输入输出样例

输入样例#1: 复制
10
输出样例#1: 复制
7


首先末尾有0肯定就是乘10,10可以分解为2和5,显然2的数目多于5,于是就是统计5的数目

然后可以转化一下,

对于

1
1 2
1 2 3
1 2 3 4
1 2 3 4 5
1 2 3 4 5 6
……
1 2 3 4 5 6 …… x

我们来除一下5,发现能被5整除的项变成了:

1
1
1
1
1
1 2
1 2
1 2
1 2
1 2
1 2 3
1 2 3
1 2 3
1 2 3
1 2 3
……
1 2 3 4 5 …… x/5
1 2 3 4 5 …… x/5
1 2 3 4 5 …… x/5
1 2 3 4 5 …… x/5
1 2 3 4 5 …… x/5

也就是5个
1
1 2
1 2 3
……
1 2 3 4 5 …… x/5

这样就可以递归求解了

另外,这次除5总共除掉了5+10+15+20+(n/5)*5个,可以用等差数列公式

对于x应该是从5k+4开始的,多余的处理掉即可 时间复杂度O(logn)

 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<algorithm>
 4 #include<cstring>
 5 #define ll long long
 6 using namespace std;
 7 int n;
 8 ll work(int x){
 9     ll ret=0;
10     for(int i=5;i<=x;i*=5){
11         ret+=x/i;
12     }
13     return ret;
14 }
15 ll find(int x){
16     if(x<5){
17         return 0;
18     }
19     if(x<10){
20         return (x-4);
21     }
22     ll ret=0;
23     while((x+1)%5){
24         ret+=work(x);
25         x--;
26     }
27     ret+=1LL*5*(x/5)*(1+(x/5))/2;
28     ret+=5*find(x/5);
29     return ret;
30 }
31 int main()
32 {
33     scanf("%d",&n);
34     printf("%lld
",find(n));
35     return 0;
36 }
原文地址:https://www.cnblogs.com/w-h-h/p/7805321.html