nyoj 954
N!
時間限制:1000?ms ?|? 內存限制:65535?KB 難度:3 描述階乘(Factorial)是一個很有意思的函數,但是不少人都比較怕它?,F在這里有一個問題,給定一個N(0<0<1000000000),求N!的二進制表示最低位的1的位置(從右向左數)。
輸入3! = (6)10 = (110)2,則第一個1是第二位
4! = (24)10 = (11000)2,則第一個1是第四位
解題思路:
在做這個題目之前,先來看一個問題:
給定一個整數N,那么N的階乘N!末尾有多少個0呢?例如:N=10,N!=362800,N!的末尾有兩個0;
?首先,最直接的算法當然是直接求出來N!然后看末尾有幾個0就行了。但這里存在兩個問題:
???? (1)不管使用long或者double一定會產生溢出。
???? (2)效率低下。
????? 對于問題(1),我們可以采用字符串存儲的辦法解決,但問題(2)是由本身算法決定的,所以只能采用其他的算法。
那 到底有沒有更好的算法呢?我們來分析,N!能產生0的質數組合只能是2 * 5,也就是說當對N!進行質數分解之后,N!末尾0的個位M取決于2的個數X和5的個數Y的最小值,即M = min(X,Y)。又因為能被2整除的數出現的頻率比能被5整除的數高得多,且出現一個5的時,最少會同時出現一個2,所以M = Y。即得出Y的值就可以得到N!末尾0的個數。
計算Y,最直接的方法,就是計算機1…N的因式分解中5的個數,然后求和。
那 么還有沒有更簡單點的方法呢?我們想,Y還能怎么樣得到?舉個例子 25的階乘中,總共有6個五,其中5,10,15,20,各貢獻一個,25貢獻兩個,也可以說成,5,10,15,20,25各貢獻一個,25又額外貢獻 一個,即5的倍數各貢獻一個5,25的倍數各貢獻一個5,即Y=[25/5] + [25/25]。同理,125中,5的倍數各貢獻一個5,25的倍數各貢獻一個5,125的倍數也各貢獻一個5,所以Y=[125/5] + [125/25] + [125/125],所以可得公式:
Y = [N/5] + [N/52] + [N/53] + …
代碼如下:long GetZeroNum(long n) {long num = 0;while(n != 0){num=num+n/5;n=n/5;}return num; }
回到這個題目上,這個題目問的是二進制中,最低位1的位置。那么最低位1之后的肯定全為0,現在就是要找到末尾有多少個0。那么我們的想法和上面一樣,找有多少個2的倍數。
AC:
#include<iostream> using namespace std;typedef long long LL;int main() { LL n,sum;while(cin>>n) {sum = 0;while(n){sum += n/2;n /= 2;}cout<<sum+1<<endl;}return 0; }
總結
- 上一篇: nyoj 998(欧拉定理的运用)
- 下一篇: 【JEECG技术文档】表单配置-树形表单