题目问我们的是满足N!的末尾恰好有K个0的最小的N是多少?
阶乘数要想凑出来0必定是有若干个2、5
由于是阶乘2的个数必定是多于5的个数。
因此我们需要去枚举5的个数
没有思路怎么办?
10!
10*9*8*7*6*5*4*3*2*1
10、5 总共是2个5
10/5=2
16!
16*15*14*...*10*...*5*...*1
15、10、5总共是3个5
16/5=3
25!
25*...*20*...*15*...*10*...*5
25、20、15、10、5总共有6个5
为什么是6个?
原因在于25可以被拆成5*5,总共是6个5。
所以我们需要反复整除5,这样才能把边界值含5的个数全部统计出来。
最后加上5的个数即可
25/5=5+5/5=6
又如125=5*5*5
一共是3个5等于**125/5
**
又如625=5*5*5*5
一共是**4
个5等于625/5
**
我们通过模拟可以发现:
我们直接对枚举到的数字整除5判断
输出能整除5是k的数字即可
但是看到k的上界为1e18直接枚举必定**TLE
**
题目要求满足N!的末尾恰好有K个0的最小的N
我们需要优化解决,当前N!恰好有k个0。
比N大的N!必定大于K个0,比N小的N!必定小于K个0。
不像最少刷题数那样,满足条件才能进行二分。
这道题直接枚举数字套模板进行二分即可。
因为题目问我们的是最少满足k个0的数字N是多少
不过最后还要检验一下二分出的答案是不是k个0
时间关系,具体看这两个大佬写的博客,写得很棒%%%
博客1
博客2
import java.util.*;
public class Main{
public static void main(String []args) {
Scanner sc=new Scanner(System.in);
long k=sc.nextLong();
long l=1,r=(long)9e18;
//数据要开大
//二分
while(l<r) {
long mid=l+(r-l)/2;
//需要再减去l
//当前的N拆分成5的倍数的个数大于等于k
//说明需要缩减范围,即r=mid
if(query(mid)>=k)r=mid;
//说明不够k需要继续寻找
else l=mid+1;
}
long x=query(r);
//再查一下N是不是能被拆成k个5
//可以的话输出r
//不可以则输出-1
if(x==k)System.out.println(r);
else System.out.println("-1");
}
static long query(long x) {
long ans=0;
//统计能拆分成5的个数
while(x>0) {
ans+=x/5;
//直接让其除以5
x/=5;
}
return ans;
}
}
反复整除法:得出某个数的阶乘含a的个数
static long query(long x) {
long ans=0;
//统计能拆分成a的个数
while(x>0) {
ans+=x/a;
//直接让其除以a
x/=a;
//再对边界x进行反复整除
//统计出x还能拆成多少个5/包含多少个5
}
return ans;
}
import java.util.*;
public class Main{
public static void main(String []args){
Scanner sc=new Scanner(System.in);
long k=sc.nextLong();
long l=1;
long r=(long)9e18;
while(l<r){
long mid=l+r>>1;
if(check(mid)>=k)r=mid;
else l=mid+1;
}
long x=check(r);
if(x==k)System.out.println(r);
else System.out.println("-1");
}
public static long check(long x){
long ans=0;
while(x>0){
ans+=x/5;
x/=5;
}
return ans;
}
}
http://t.csdn.cn/2WxI4
https://blog.csdn.net/weixin_57943259/article/details/124206177