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

目录

  • 1.求阶乘
    • 1.问题描述
    • 2.输入格式
    • 3.输出格式
    • 4.样例输入
    • 5.样例输出
    • 6.数据范围
    • 7.原题链接
  • 2.解题思路
  • 3.AC_code
    • C++
    • Java

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 1\leq K \leq 10^{18} 1K1018

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 的个数时,先筛选出能拆分出 15 的数有哪些,再筛出能拆分 25 的倍数有哪些,以此类推。如2x5=10,说明10可以拆出15,如5x5=25,说明25可以拆出25。这样我们只需要不断的将 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
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) << '\n';
}
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;
    }
}

.

你可能感兴趣的:(蓝桥真题,蓝桥杯,算法,java,c++,1024程序员节)