1. 程式人生 > 實用技巧 >階乘末尾0的個數(二分+數論)

階乘末尾0的個數(二分+數論)

設計一個演算法,計算出n階乘中尾部零的個數

樣例
11! = 39916800,因此應該返回 2

挑戰
O(logN)的時間複雜度

要判斷末尾有幾個0就是判斷可以整除幾次10。10的因子有5和2,而在0~9之間5的倍數只有一個,2的倍數相對較多,所以本題也就轉換成了求N階乘中有幾個5的倍數。比如10的階乘,10之內有2個5的倍數,10/5=2,2之內則沒有了可以匹配的5了,所以一共2個5。

還有25階乘中貢獻了6(25/5+5/5)個5,因為有5的倍數的倍數(25=5*5,貢獻2個5),所以就有了count += n/5,在先求一批5的個數後,再求第二批5的個數。

同理 125中 5的個數等於125/5 + 25/5 +5/5=31;

參考部落格

#include<iostream>
using namespace std;
int main()
{
    int n;
    cin>>n;
    int count = 0;
    while(n)
    {
        n /= 5;     //算出當前數字中可以匹配5(5和5的倍數)的個數
        count += n; //累加之
    }
    cout<<count;
    return 0;
}

n的階乘尾部有q個連續的0,現在給你q,請你算出滿足條件的n,如果有多個n滿足條件,輸出最小的那個即可。

Input

輸入一個T(T <= 10000),表示樣例數量。

每個樣例輸入一個q。(1 <= q <= 100,000,000)

Output

對於每個樣例,輸出滿足條件的最小的n,如果沒有滿足條件的則輸出"impossible"。.

Sample Input

3

1

2

5

Sample Output

Case 1: 5

Case 2: 10

Case 3: impossible

解析:因為階乘中0的個數是按照數的增大而遞增的(滿足單調性)

#include<iostream>
#include<algorithm>
using namespace std;
//因為0的個數是隨這數的增加而增加的
int judge(int x){ int ans=0; while(x){ ans+=x/5; x/=5; } return ans; } int main(){ int t,n; cin>>t; int kase=0; while(t--){ cin>>n; int l=0,r=1e9; int ans=0; while(l<=r){ int mid=(l+r)/2; int p=judge(mid); if(p>=n){ r=mid-1; ans=mid; } else{ l=mid+1; } } ans=(ans-ans%5);//因為是最小的那個 if(judge(ans)==n) printf("Case %d: %d\n",++kase,ans); else{ printf("Case %d: impossible\n",++kase); } } }