N!的k进制位数 【打表】or【斯特林公式】

N!的位数
Time Limit:1000MS Memory Limit:131072KB 64bit IO Format:%lld & %llu
Submit

Status
Description
我们知道n!=n*(n-1)(n-2)…*2*1。

那么给定一个n,n!是几位数呢。

更困难的,n!的k进制数有多少位呢。

Input
第一行是一个数T(1≤T≤50000),代表T组测试数据。

每一组测试数据占一行,有两个整数n(0 ≤ n ≤ 10^6),k(2≤k≤1000)。

Output
对于每组测试数据,输出n!k进制数的位数。

Sample Input
2
3 10
3 2
Sample Output
1
3

我们都知道10进制下一个数x的位数为(int)log10(x)+1(不信的话,你可以找几个数来看看) ,所以类比得 k进制下一个数的位数为(int)logk(x)+1 。
现在要求一个数的阶乘的k进制下的位数。即 ( int )logk(x!) + 1

思路一:打表
因为计算机中没有以任何数为底的对数运算,所以我们要先换底公式
logk(x!) +1 = log(x!) / log(k) +1
log(x!) =log(1.0)+log(2.0)+log(3.0) .… .+log(x.0);
然后合并最后的 答案
ans = ( int ) ( (log(x!) =log(1.0)+log(2.0)+log(3.0) .… .+log(x.0)) / log(k) )+1
但是每次运算都要从1算到x,太费时间了,所以我们可以打表,以空间换时间。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<vector>
#include<set>
#define CLR(a,b) memset((a),(b),sizeof(a))
#define inf 0x3f3f3f3f
#define mod 100009
#define LL long long
#define M  10000000
#define ll o<<1
#define rr o<<1|1
#define lson o<<1,l,mid
#define rson o<<1|1,mid+1,r
using namespace std;
void read(int &x){
    x=0;char c;
    while((c=getchar())<'0');
    do x=x*10+c-'0';while((c=getchar())>='0');
}
double a[M];
void dabiao()
{
    double d=0;
    a[0]=0.0;
    for(int i=1;i<M;i++)
    {
        d+=log(i);
        a[i]=d;
    }
}
int main()
{   
     dabiao();
     int t;
     scanf("%d",&t);
     while(t--)
     {
        int n,m;
        scanf("%d%d",&n,&m); 
        printf("%d\n",int(a[n]/log(m))+1);
     }

    return 0;
}

思路二 : ( int )logk(x!) + 1
用斯特林公式
斯特林公式 为: N! = sqrt(2 * PI * n ) * ( n / e ) ^n
还是首先用换底公式
logk(x!) = log(x!) / log(k)
然后将 n!的近似公式带入得
ans = ( 0.5 * log ( 2 * PI * n ) + n * log( n / e ) )/ log(k) + 1
这样的话就可以 o(1) 得 。

代码

#include<bits/stdc++.h>
using namespace std;
#define LL long long

const int N =1e6+11;
const int M = 2e6+11;
const int mod = 998244353;
const int inf = 0x3f3f3f3f;
const double  PI = acos(-1.0);
const double  E  = exp(1.0);

int main(){
   // cout<<PI<<"\n";
    int t ;scanf("%d",&t);
    while(t--){
        double n,k;scanf("%lf%lf",&n,&k);
        double ans=0.5*log(2*PI*n)+n*log(n/E);
        ans/=log(k);
        if(n==0) printf("%d\n",1);
        else printf("%d\n",int(ans)+1);
    }
return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值