ZCMU—1375

来源:互联网 发布:windows ping包 编辑:程序博客网 时间:2024/06/11 05:52

1375: 阶乘的零

Time Limit: 1 Sec  Memory Limit: 128 MB
[Submit][Status][Web Board]

Description

定义f(n)为n!的末尾零的个数,例如f(4)=0,f(5)=1。你的任务是对于一个给定的的值x找出最小的n满足f(n)=x。

Input

多组测试数据,每组测试数据包含一个正整数x(1<=x<=10^8)。

Output

对于每组测试数据输出对应的n,若没有n满足则输出“No solution”。

Sample Input

2

Sample Output

10

HINT

water problem!

【分析】

首先...我们要会算n!有几个0,显然有几个0取决于n!这个数中因子2的个数和因子5的个数,显然2的个数远大于5,所以只要考虑因子5的个数就可以了~当然不能用n的算法...需要log5(n)的速度...

对N进行质因数分解 N=2^x * 3^y * 5^z...,由于10 = 2*5,所以末尾0的个数只和x与z有关,每一对2和5相乘可以得到一个10,于是末尾0的个数=min(x,z)。在实际中x是远远大于z的,所以我们只要求出z的值即可。
根据公式
z = N/5 + N/5^2 + N/5^3+...+N/5^k
这表明,5的倍数贡献了一个5,5^2的倍数又贡献了一个5...
比如:25其实是贡献了2个5,但是在N/5中已经贡献了一个,所以在N/5^2中再贡献一个;同样,125在N/5中贡献一个,在N/5^2中贡献一个,在N/5^3中再贡献一个,一共是3个。
知道这点之后就容易了,这道题显然是有数学公式可以直接求答案的...但是因为我比较懒所以写了个二分直接查答案了...因为上面这个算n!末尾0个数的速度太快了,加上二分基本上也属于常数算法...所以....嗯直接搜吧!手动给一个极大的区间然后搜就好了

【代码】
#include <stdio.h>long long find(long long x){long long ans=0;while (x){ans+=x/5;x/=5;}return ans;}int main(){long long n;while (~scanf("%lld",&n)){long long left=5;long long right=1000000000000;while (left<right){long long mid=(left+right)/2;long long m=find(mid);if (m==n){while (mid%5) mid--;printf("%lld\n",mid);goto out;}if (m>n) right=mid-1;else left=mid+1;}printf("No solution\n");out:;}}


0 0