求n^n和n!的最左边的数字

原文出自:http://hi.baidu.com/matrush/item/aa83b1db96b131ff92a97427


[RQNOJ499]阶乘最高位

求n^n和n!的最左边的数,核心思想就是取10为底的对数推公式,n!还要用到斯特灵近似公式。

推广:求左边第x位只要推公式时将10^(k-1)变为10^(k-x)即可,最后答案取模10。

//n^n最左位
n^n的位数:k = [lg(n^n)] + 1 = [n * lg(n)]
最左边的数作个位:x = n^n / 10^(k-1)
取对数:lg(x) = n * lg(n) - (k-1) = (n*lg(n) - [n*lg(n)])
最左边的数:[x] = [10^lg(x)] = [10^(n*lg(n) - [n*lg(n)])]

//n!最左位
n!的位数:k = [lg(n!)] + 1
最左边的数作个位:x = n! / 10^(k-1)
取对数:lg(x) = lg(n!) - (k-1) = lg(n!) - [lg(n!)]
最左边的数:[x] = [10^lg(x)] = [10^(lg(n!) - [lg(n!)])]
n!将会很大,所以要用Stirling公式近似计算
Stirling公式:lim(n→∞) √(2πn) * (n/e)^n / n! = 1
也就是说当n趋于无穷大的时候,n!与√(2πn) * (n/e)^n的值十分接近
所以lg(n!) = lg(√(2πn) * (n/e)^n) = 1/2*(lg(2π) + lg(n)) + n * (lg(n) - lg(e))
代入[x] = [10^lg(x)] = [10^(lg(n!) - [lg(n!)])]即可。

提示:log10(d) = log(d)/log(10.0)

代码:

#include <iostream>
#include <cmath>
using namespace std;
const double PI = acos(-1.0);
const double e = exp(1.0);
int main() {
    int n;
    while (scanf("%d", &n) != EOF && n) {
       //n^n
        double a = n * log10(n);
        printf("%d\n", (int)pow(10.0, a - (long long)a));
       //n!
        double b = (log10(2 * PI) + log10(n)) / 2 + n * (log10(n) - log10(e));
        printf("%d\n",(int)pow(10.0,b - (long long)b));
    }
}



你可能感兴趣的:(求n^n和n!的最左边的数字)