UVA10061求不同进制的n!的数字位数和末尾零的个数
2015-08-04 21:25
447 查看
这题自己做的话估计很难做出来,本人比较菜,而且智商不够,
同时看了别人题解了解了下斯特林公式,虽然此题并不能用斯特林公式,精度问题会WA,
介绍下斯特林公式:
普通计算时:
N!=1*2*3*4*5*............*N;
如果要计算N!后得到的数字,则我们可以知道其等于lgN!+1
lgN!=lg1+lg2+lg3+lg4+lg5+....................+lgN;
但是当N很大的时候,我们可以通过数学公式进行优化:(即Stirling公式)
N!=sqrt(2*pi*N)*(N/e)^N;(pi=3.1415926=acos(-1.0),e=2.718)
lgN!=(lg(2*pi)+lgN)/2+N*(lgN-lge);
斯特林公式可以用来估算某数的大小结合lg可以估算某数的位数,或者可以估算某数的阶乘是另一个数的倍数。
此题计算位数是一位位求log10,然后进制问题就用换底公式,也要注意最后加个eps的精度问题,不然会WA,
至于求末尾零,是此题最精妙的地方,我们知道当阶乘的值有多少个b就会有多少个零,显然这题不能算出来n!,
然而可以把n!里面的数逐个分解质因数,因为任意一个合数都能由他前面的质数相乘得到,所以题中的方法相等于分解
n!的质因数和b!的质因数,因为大于b的质因数并不会对于末尾零产生影响所以不管,最后用min(fn[i]/fb[i],ansb)就可以求出最多
可以形成多少对b,也即末尾零的个数。
同时看了别人题解了解了下斯特林公式,虽然此题并不能用斯特林公式,精度问题会WA,
介绍下斯特林公式:
普通计算时:
N!=1*2*3*4*5*............*N;
如果要计算N!后得到的数字,则我们可以知道其等于lgN!+1
lgN!=lg1+lg2+lg3+lg4+lg5+....................+lgN;
但是当N很大的时候,我们可以通过数学公式进行优化:(即Stirling公式)
N!=sqrt(2*pi*N)*(N/e)^N;(pi=3.1415926=acos(-1.0),e=2.718)
lgN!=(lg(2*pi)+lgN)/2+N*(lgN-lge);
斯特林公式可以用来估算某数的大小结合lg可以估算某数的位数,或者可以估算某数的阶乘是另一个数的倍数。
此题计算位数是一位位求log10,然后进制问题就用换底公式,也要注意最后加个eps的精度问题,不然会WA,
至于求末尾零,是此题最精妙的地方,我们知道当阶乘的值有多少个b就会有多少个零,显然这题不能算出来n!,
然而可以把n!里面的数逐个分解质因数,因为任意一个合数都能由他前面的质数相乘得到,所以题中的方法相等于分解
n!的质因数和b!的质因数,因为大于b的质因数并不会对于末尾零产生影响所以不管,最后用min(fn[i]/fb[i],ansb)就可以求出最多
可以形成多少对b,也即末尾零的个数。
#include<cstdio> #include<iostream> #include<vector> #include<queue> #include<algorithm> #include<string> #include<cstdlib> #include<map> #include<set> #include<cmath> #include<cstring> #include<cctype> #include<climits> #include<memory> #include<climits> #include<cstdlib> using namespace std; #define LL long long #define INT (1LL<<62); const int N=805; int main() { LL n,b; LL fn ,fb ; while(cin>>n>>b) { memset(fn,0,sizeof(fn)); memset(fb,0,sizeof(fb)); LL tempb=b; for(int i=2;i<=b;i++) while(tempb%i==0) { tempb/=i; fb[i]++; } for(int i=2;i<=n;i++) { LL tempn=i; for(int j=2;j<=b;j++) { while(tempn%j==0) { fn[j]++; tempn/=j; } } } // LL tt=INT; // cout<<tt<<endl; LL ansb=INT; for(int i=0;i<=b;i++) if(fb[i]!=0) ansb=min(ansb,fn[i]/fb[i]); double ansd=0; for(int i=1;i<=n;i++) ansd+=log10(i); LL ansdd=floor(ansd/log10(b*1.0))+1; //cout<<ansb<<' '<<ansdd<<endl; printf("%lld %lld\n",ansb,ansdd); } return 0; }
相关文章推荐
- DPDK 收发包处理流程(二)(网卡初始化)
- Nginx+Keepalived实现Web服务器负载均衡
- ZOJ 题目2734 Exchange Cards(DFS 去重OR 母函数)
- 命令模式
- rsync使用(二)
- NOI2011 兔兔与蛋蛋游戏
- BFS(最短路) HDU 2612 Find a way
- (剑指Offer)面试题55:字符流中第一个不重复的字符
- 黑马程序员——Java 面向对象_继承
- C#网络编程《二》
- HDU5340.MZL's simple problem
- DPDK 收发包处理流程(一)(网卡驱动注册)
- TF-IDF
- iOS开发——UI进阶篇(十五)Quartz2D介绍
- HDU1001
- 树的广度优先遍历与深度优先遍历算法
- 解决virtul box 无法调大分辨率的方法
- 2015.08.04学习日记
- When you are old
- android studio 怎么引入签名文件