Trailing Zeroes (III) (数论(二分查找值,规律))

题目来源:https://vjudge.net/problem/LightOJ-1138
【题意】
求一个尽可能小的数n,其阶乘的后面有q个0。
【思路】
一开始推得数学公式,然后想错了,,,错了几发。。也是蛮尴尬的。。
然后,找了小伙伴一起讨论了下,答案就出来了。。。
思路是这样的,若是满足一个数尽可能小,并且阶乘后面还有q个0,那么这个数一定是5的倍数,因为只有2*5才有0。。。根据这个,试着推了几组数据,发现,如果是按照每次加5递增排列的话,比如:5 10 15 20 25 30 35 40 45 50 55 60 65 70 75 80 85 90 95 100 105 110 115 120 125。。。会发现哦,一开始0的个数是每次增加1的,到了25,突然增加2,然后还是增加1,到了50突然增加2,然后还是1,然后是75,然后是100,而到125的时候突然增加3,然后还是增加一,然后到了150的时候增加2。。发现没?如果是单纯是5的倍数,每次都只是加1,如果是25的倍数,就在原来5的基础上再加1,是125的倍数的话就在5,25的基础上在加一。。。然后等等等等。。。然后发现,5是5的一次方,25是5的二次方,125是5的三次方。。。
恩,我们只需要二分找一个数,保证它的值除以5,除以25,除以125。。。之后的和是q就可以。。但是有一点,,他可能得到的不是最小值,也就是说不是5的倍数,但是只需要除以5在乘以5就可以了。
然后,,,感觉也没啥记录的了、、、
总而言之,言而总之,A完这道题也是蛮开心的。。。
【代码】

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
const int INF=1e9;
typedef unsigned long long ll;
typedef long long LL;
int main()
{
    int T,cases=1;
    scanf("%d",&T);
    while(T--)
    {
        int q;
        LL ans=-1;
        scanf("%d",&q);
        int l=1,r=q*5,mid;//为什么右端点是q*5,因为q*5>=ans.想一想为什么(hint:刚才那个序列。。。)
        while(l<=r)
        {
            mid=(l+r)/2;
            int m=mid,wu=5,count=0;
            while(m>=wu)
            {
                int p=m;
                p/=wu;
                count+=p;
                wu*=5;
            }
            if(count==q)
            {
                ans=mid;
                break;
            }
            else if(count>q)
                r=mid-1;
            else
                l=mid+1;
        }
        if(ans==-1)
            printf("Case %d: impossible\n",cases++);
        else
            printf("Case %d: %lld\n",cases++,ans/5*5);
    }
}

你可能感兴趣的:(ACM竞赛,【含有数学思想】,ACM的进程)