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