第十三届蓝桥杯JavaB组省赛E题——求阶乘 (AC)

1.求阶乘

1.问题描述

满足 N ! N ! N! 的末尾恰好有 K K K 个 0 的最小的 N N N 是多少?

如果这样的 N N N 不存在输出 − 1 -1 −1 。

2.输入格式

一个整数 K K K 。

3.输出格式

一个整数代表答案。

4.样例输入

2

5.样例输出

10

6.数据范围

1 ≤ K ≤ 1 0 18 1leq K leq 10^{18} 1≤K≤1018

7.原题链接

2.解题思路

注意到 k k k 的值最大达到1e18,这意味着我们最多只能使用 O ( l o g n ) O(logn) O(logn) 的复杂度,这个复杂度的算法我们应该直观地想到二分。

既然想使用二分,那就需要考虑是否满足二段性,设 n n n 为答案,当 m i d mid mid 小于 n n n 时, m i d mid mid阶乘末尾 0 的个数一定小于 k k k ,当 m i d mid mid 大于等于 n n n 时, , m i d ,mid ,mid 阶乘末尾 0 的个数一定 不小于 k k k 。由此可知这是符合二段性的,说明我们可以二分 。

当然判断某个数的阶乘的末尾 0 个数,我们也不能暴力的去计算,一个比较常用的技巧则是判断一个数可拆分出 2 2 2 的个数和 5 5 5 的个数,由于是阶乘,可知 2 2 2 出现的次数一定比 5 5 5 多,所以我们只需要看 n ! n! n! 能拆分出多少个 5 5 5 ,则可知它的阶乘有多少个 0。

在计算 n ! n! n! 可以拆分多少个 5 5 5 的个数时,先筛选出能拆分出 1 个 5 的数有哪些,再筛出能拆分 2 个 5 的倍数有哪些,以此类推。如2x5=10,说明10可以拆出1个5,如5x5=25,说明25可以拆出2个5。这样我们只需要不断的将 n 除以 5 并累计结果,即可在 l o g log log 的复杂度计算出结果。

最后二分得到的答案还需要判断阶乘末尾0的个数是否恰好为 k k k 个,因为我们只能保证不少于 k k k 个,并不一定恰好是 k k k 个。

同时需要注意二分的上界 r ,需要保证足够大才能得到答案,可以自己猜一下然后看能否跑出 k k k= 1e18 时的答案,这里开的 1e20 。 时间复杂度:可视为 O ( l o g ( 1 e 20 ) ∗ l o g n ) O(log(1e20)*logn) O(log(1e20)∗logn)

3.AC_code

C++

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef unsigned long long uLL;
LL query(LL x)
{
          
   
    LL ans = 0;
    while (x > 0) {
          
   
        ans += x / 5;
        x /= 5;
    }
    return ans;
}
LL k;
void solve()
{
          
   
    cin >> k;
    LL l = 1, r = 1e20;
    while (l < r)
    {
          
   
        LL mid = l + (r - l) / 2;
        if (query(mid) >= k) r = mid;
        else l = mid + 1;
    }
    LL x = query(r);
    cout << (x == k ? r : -1) << 
;
}
int main()
{
          
   
    ios_base :: sync_with_stdio(false);
    cin.tie(nullptr);
    int t = 1;
    while (t--)
    {
          
   
        solve();
    }
    return 0;
}

Java

import java.util.Scanner;

public class Main {
          
   
    public static void main(String[] args) {
          
   
        Scanner sc = new Scanner(System.in);
        long k = sc.nextLong();
        long l = 1, r = (long) 1e20;
        while (l < r) {
          
   
            long mid = l + (r - l) / 2;
            if (query(mid) >= k) r = mid;
            else l = mid + 1;
        }
        long x = query(r);
        System.out.println(x == k ? r : -1);
    }

    static long query(long x) {
          
   
        long ans = 0;
        while (x > 0) {
          
   
            ans += x / 5;
            x /= 5;
        }
        return ans;
    }
}

.

经验分享 程序员 微信小程序 职场和发展