题目网址:http://class.51nod.com/Challenge/Problem.html#problemId=2652
一、题目描述
给出一个数k,求最小的n,使得n的阶乘后面0的数量>=k。
例如k=1,5的阶乘 = 1*2*3*4*5 = 120,120后面有1个0。并且4的阶乘后面没有0,所以5是最小的结果。
输入
一个数k(1 <= k <= 10^9)
输出
输出最小的满足条件的n。
样例输入
1
样例输出
5
二、思路描述
我们先列个表来看看有什么规律。表如下:
k | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
n | 5 | 10 | 15 | 20 | 25 | 25 | 30 |
我们发现n和k都是升序的(具有单调性)。只要是具有单调性的我们就可以用二分答案来做这道题。左端点(l)在最左边(1),右端点(r)在最右边(1012)。
假设我们要找的数字是mid,(mid =(l + r)/ 2)那么我们要判断mid的阶乘末尾的零的数量是比k大还是比k小。
如果比k小了,说明mid这个数字小了,得往大了找,左端点往右挪。
如果比k大了,说明mid这个数字大了(也有可能正好等于k),得往小了找,右端点往左挪
我们可以在1~1012这些数中进行二分查找,步骤如下:
1、mid = (1+1012)/ 2。(也可以想做mid = (l + r)/ 2)
2、如果mid阶乘的末尾有sum个零,而且sum >= k (比我们想要的多,可以试着减少,右端点往左挪),r = mid。
3、如果mid阶乘的末尾有sum个零,而且sum < k (比我们想要的少,可以试着扩大,左端点往右挪),l = mid。
4、现在的问题就是如何判断mid的阶乘末尾有多少个零,这跟我们以前学的那道题一样:https://www.cnblogs.com/elisa02/p/12811208.html。
我们用我们以前那道题的思路改写个函数来判断有多少个零就可以了
5、那么我们最后输出什么呢?
l实际上是不符合题目要求(“不合法”)的。l最后肯定是 < k的,所以我么最后得输出r。因为r是>= k的,符合题目要求(“合法”)
三、提示
这道题得开long long,要不然不能AC。
r的初始值得=1e12,要不然也不能AC。
四、代码
#include<cstdio> #include<iostream> using namespace std; long long k, l=1, r=1e12; long long zero(long long n){//计算n的阶乘末尾有多少个零 long long cur = 5, sum = 0; while(n >= cur){ sum += n / cur; cur = cur * 5; } return sum; } int main(){ cin >> k; while(l < r-1){ long long mid = (l+r) / 2;// if(zero(mid) < k){//如果0还不够 l = mid;//往大了找 }else{//如果0太多了 r = mid;//往小了找 } } cout << r << endl; return 0; }