阶乘末尾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);
        }
    }
}

 

posted @ 2020-11-01 22:31  哎呦哎(iui)  阅读(456)  评论(0编辑  收藏  举报