Trailing Zeroes

题目:

Trailing Zeroes 

You task is to find minimal natural number N, so that N! contains exactly Q zeroes on the trail in decimal notation. As you know N! = 1*2*...*N. For example, 5! = 120, 120 contains one zero on the trail.

Input

Input starts with an integer T (≤ 10000), denoting the number of test cases.

Each case contains an integer Q (1 ≤ Q ≤ 108) in a line.

Output

For each case, print the case number and N. If no solution is found then print 'impossible'.

Sample Input

3

1

2

5

Sample Output

Case 1: 5

Case 2: 10

Case 3: impossible

题解:

解法一:

这是一个二分经典题,主要思路为定义一个求n!后面0的数量的函数,然后二分。为什么要二分呢,因为你用朴素算法方法求的话,每次都要循环1e8次,肯定会TL,用二分查找可以快很多。

(二分搜索,在有序序列查找值上非常方便。通过一次比较,可以把解的范围缩小一半。反复与区间的重点进行比较,就可以不断把解的范围缩小到原来的一半,最终在O(logn)次的比较之内求得最终的解。)

求n!后面0的数量请参考我的CSDN博客中的一篇文章:https://blog.csdn.net/qq_45328552/article/details/98206579

我会在代码里分析一下二分。

#include <iostream>

using namespace std;

typedef long long ll;

int search(ll n)
{
    int sum = 0;
    
    while(n)
    {
        sum += n/5;
        n /= 5;
    }
    
    return sum;
}

int main()
{
//    freopen("input.txt","r",stdin);    //注释!注释!!! 
    
    int t, n;
    
    cin >> t;
    
    for(int i = 1; i <= t; i ++ )
    {
        cin >> n;
        
        ll head = 0, tail = 5e8 + 5, mid; 
        //定义二分的头和尾及mid,注意定义成long long类型,因为二分一般都是求非常大的数 
        while(head <= tail) //二分循环需要满足的条件,头小于尾 
        {
            mid = (head + tail) / 2;  
            
            if(search(mid) < n) head = mid + 1; //search(mid)小于n,则所求值必在右边,mid以及mid左边的数都不满足,因此让头等于mid+1 
            else if(search(mid) > n) tail = mid - 1; //search(mid)大于n,所求值必在左边,mid及mid右边的数都不满足,因此让尾等于mid-1 
            else break; //等于则跳出循环,因为已经确定了要找的值 
        }
        
        if(head > tail) printf("Case %d: impossible\n", i); //head > tail找到不满足条件还找不到,说明已经完全二分还找不到符合条件的数,输出false 
        else printf("Case %d: %d\n", i, mid - mid % 5);    //根据上面的代码可以知道这是search(mid)=n符合条件的值,输出即可 
    }    //输出mid-mid%5的原因是阶乘后面0的数量相同的数会有重复的而这里要求满足条件的最小值6、7、8和5的阶乘后面0的数量是相同的,6、7、8减去6、7、8 % 5后就变成满足条件的最小值了                        
    return 0;
}

 解法二:

我同学用了打表的方法做出了这道题,也是很强了。打表的时候看着数据4、5一组很慢、很慢地通过,最后成功AC,真的很爽。

打表注意事项:1、明白阶乘为0的数量的最小数为5的倍数,从而以5为倍数进行循环。

2、提前打好表,使用标记数组的思维去打表。不要在循环体内一次一次地去打表,肯定TL;

#pragma GCC optimize(2)
#include <bits/stdc++.h> 
using namespace std;

typedef long long ll;
const int N=1e8+10;

int f[N];

int search(int n)
{
    int num = 0;
    while(n)
    {
        num+=n/5;
        n/=5;
    }
    return num;
 } 

int main()
{
//    freopen("input.txt", "r", stdin);
    //提交时注释,调试时取消注释!!! 
    int t;
    cin >> t;
    for(int i=5;i<1e8+10;i+=5)
    {
        f[search(i)]=i;
    }
    int tmp;
    for(int i=0;i<t;i++)
    {
        scanf("%d",&tmp);
        if(f[tmp]!=0) printf("%d\n",f[tmp]);
        else printf("impossible\n");
    }        
    return 0;
}

 

皓齿蛾眉,命曰伐性之斧。 --《吕氏春秋 》

posted @ 2019-08-02 20:01  pioneer1  阅读(95)  评论(1编辑  收藏  举报