Trailing Zeroes (III) LightOJ - 1138
考察:思维+二分
错误思路:
根据分析可以发现当n为5的倍数时,n!会多>=1个0.如果n能分解k个5.那么会在(n-5)!的基础上多k个0.看到这里可能会想到前缀和预处理,但是当n=1e8时,它的0还未到1e8个.如果用数组存储会MLE.
正确思路:
不能预处理只能每个每个地算,但是每次都每5个找一个是不现实的.可以发现n越大阶乘的0越多,也就是说这种性质有显然的单调性.因此用二分处理.那么如何找1~n的所有能分解出5的个数呢?联想到阶乘分解那道题.5的倍数有n/5个,贡献2个5的有n/25个.与上道题的阶乘分解的思想相同.可以让n/=5或t*=5求解能够分解多个5的数的贡献
注意:
n/25是不需要*5的,因为n/5已经算了一次
虽然代码写的是t*=5,但是用n/=5更好
1 #include <iostream> 2 #include <cstring> 3 #include <algorithm> 4 using namespace std; 5 typedef long long ll; 6 ll check(ll n) 7 { 8 int ans = 0;ll t = 5; 9 while(n/t!=0) 10 { 11 ans+=n/t; 12 t*=5ll;//k次5看是否有 5^k的倍数 因为5的倍数在每次除的时候都去掉了一个5的因子 13 } 14 return ans; 15 } 16 int main() 17 { 18 int T,kcase = 0,m; 19 scanf("%d",&T); 20 while(T--) 21 { 22 scanf("%d",&m); 23 ll low = 5,high = 1e9; 24 while(low<high) 25 { 26 ll mid = (low+high)/2; 27 if(check(mid)>=m) high = mid; 28 else low = mid+1; 29 } 30 if(check(low)==m) printf("Case %d: %lld\n",++kcase,low); 31 else printf("Case %d: impossible\n",++kcase); 32 } 33 return 0; 34 }