题目来源: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<set>
#include<map>
#include<stack>
#include<cmath>
#include<queue>
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<limits.h>
#include<algorithm>
#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);
}
}