想必大家都知道n!很容易爆long long吧,n = 23时(unsigned long long)也束手无策。但很多时候我们又要用到n!。
一. 斯特灵公式:
这个公式的证明用到了高数极限的知识和Wallis公式,这里就不再赘述。再看斯特林公式的更准确的表达:,n越大,n!越准确,实际上n比较小时,斯特林公式也很近似。
1) 牛客网:https://www.nowcoder.com/acm/contest/75/A
题意:求n!在8进制下的位数。
思路:我们求一个10进制数的位数时怎么求,log10(n)+1就是答案。同理,log8(n!)+1就是此题的解。
AC代码:
#include<iostream>
#include<cstdio>
#include<cmath>
#define e exp(1)
using namespace std;
double pi=acos(-1.0);
int main()
{
int n,t;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
if(n==0)
{
puts("1");
continue;
}
int ans= (log10(2*n*pi)/2+n*log10(n/e))/log10(8) ;//对数的性质+斯特灵公式
printf("%d\n",ans+1);
}
return 0;
}
2)牛客网:https://www.nowcoder.com/acm/contest/185/F
题意很清楚。
思路:用斯特灵公式表示n!,对两边去对数,再二分找n值。
AC代码:
#include<iostream>
#include<cmath>
using namespace std;
typedef long long ll;
double e = exp(1);
double pi=acos(-1.0);
inline double Stirling(ll n) //斯特灵公式取对数
{
return log(2*n*pi)/2+n*log(n/e);
}
int main()
{
ll x;
while(cin>>x)
{
double tep = x*log(x); //对x^x对数,等式左右都取对数并不影响结果
ll l=x,r=2*x; //二分的左右边界,根据 x! < x^x < (2*x)!而来
while(1)
{
ll mid=(l+r)/2;
if(Stirling(mid-1)<tep&&Stirling(mid)>tep) mid-1小于,并且mid大于,mid一定是最小
{
cout<<mid<<endl;
break;
}
if(Stirling(mid)<tep) l=mid+1;
else r=mid-1;
}
}
return 0;
}