1. 程式人生 > >洛谷P2388 階乘之乘

洛谷P2388 階乘之乘

include () 應該 遞歸 std sample range print code

題目背景

不告訴你……

題目描述

求出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\n",find(n)); 35 return 0; 36 }

洛谷P2388 階乘之乘