關于這道題,見過兩種問法:
- 給定參數n(n為正整數),請計算n的階乘n!末尾所含“0”的個數。
- (n!%(10^k)) == 0。已知n,求能使上式成立的K的最大值。
問題分析:
顯然,對于階乘這個大數,我們不可能将其結果計算出來,在統計其末尾所含有的“0”的個數。是以必須從其數字特征進行分析。
首先考慮一般的情形。對于任意一個正整數,若對其進行因式分解,那麼其末尾的“0”必可以分解為2*5。這裡每一個“0”必然和一個“2”與“5”對應。這裡是階乘,含有2的分解比含有5的分解多很多。是以這道題的是問:正整數n因式分解中“5”的個數。例如6的階乘:
6! = 6 * 5 * 4 * 3 * 2 * 1
分解後
6! = (3*2)*5*(2*2)*3*2*1 = 5*3*3*2*2*2*2*1
從上面的例子可以看出,分解之後6的階乘含有一個5,四個2,2的個數5多很多。
對于n<5,因為不含分解因子“5”,是以末尾沒有0。
但是對于n>=5的情況呢?我們可以把含有分解因子為“5”的給提出來,把n!變為
n! = [5m*5(m-1)*....*10*5]*a,a是一個不含因子“5”的整數,其中n = 5m + r (0<= r <= 4)
例如26的階乘:
26! = [25*20*15*10*5]*26*24*23*22*21*19*......*1
26! = [(5*5)*(5*4)*(5*3)*(5*2)*5]*26*24*23*22*21*19*......*1
26! = [(5*5)*(5*4)*(5*3)*(5*2)*5]*a(a代表後面所有數相乘)
通過上面的分解我們很容易看出26的階乘一共有6個分解因子“5”。但是特别大的正整數呢?我們可不能手寫出來然後數個數,是以我們還要進一步分析。
當 m>=5 時,m本身也可以分解出“5”,是以我們需要在原有的基礎上再加m分解後的“5”的個數,現在n的階乘可以寫為:
n! = 5^m * m! * a
推導過程是:
n! = [5m*5(m-1)*....*10*5]*a = [5*5*5....*5*m*m-1*m-2*.....*1]*a
整合之後得到
n! = 5^m * m! * a
通過上面的推導,我們可以得出最終的公式,令f(x)表示正整數x末尾所含有的“0”的個數, g(x)表示正整數x的因式分解中因子“5”的個數:
f(n!) = g(n!) = g(5^k * k! * a) = k + g(k!) = k + f(k!)
是以,最終的計算公式為:
當0 < n < 5時,f(n!) = 0;
當n >= 5時,f(n!) = k + f(k!), 其中 k = n / 5(取整)
到這裡代碼就寫了,這不是遞歸調用嘛,是以代碼寫為:
int func(const int x)
{
if ( x < 5)
{
return 0;
}
int y = x / 5;
return y + func(y);
}
但是遞歸調用涉及到函數的調用開銷,效率并不高,我們既然有公式了,可以直接帶入公式:
int func2(int x)
{
int y = 0;
while (x > 4)
{
x = x / 5;
y += x;
}
return y;
}
還有一種寫法,我覺着比較難了解:
int func3(const int x)
{
int y = 0;
for (int i = 5; i <= x; i *= 5)
{
y += x / i;
}
return y;
}
感謝大家,我是假裝很努力的YoungYangD(小羊)。
參考資料:
https://www.cnblogs.com/hutonm/p/5624996.html