这题自己做的话估计很难做出来,本人比较菜,而且智商不够,
同时看了别人题解了解了下斯特林公式,虽然此题并不能用斯特林公式,精度问题会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[N],fb[N];
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;
}

本文介绍斯特林公式及其应用,并通过一个具体的编程实例讲解如何利用斯特林公式来估算大数阶乘的位数及计算阶乘末尾零的数量。

被折叠的 条评论
为什么被折叠?



