POJ 1423 Big Number 解题报告

来源:互联网 发布:linux snmp协议 编辑:程序博客网 时间:2024/04/29 20:33

 

还以为是普通的高精度,结果Time Limit Exceed了。

one integer 1 <= m <= 10^7 on each line. 这个数量级不可能AC了。

#include<stdio.h>
#
define MAX 100
int main()
{
    int n
, m, i, j, base, set;
    int a[
MAX];
    scanf(
"%d", &n);
    
while(n--)
    {
        scanf(
"%d", &m);
        base 
= m;
        memset(a
, 0, sizeof(a));
        
for(i=0; base>0; i++, base /= 10)
            a[i] 
= base % 10;
        
for(i=m-1; i>=1; i--)
        {
            set 
= 0;
            
for(j=0; j<MAX; j++)
            {
                set 
= a[j] * i + set;
                a[j] 
= set % 10;
                set 
/= 10;
            }
        }
        
for(i=MAX-1; i>=0; i--)
        {
            
if(a[i] != 0)
                
break;
        }
        
printf("%d/n", i+1);
    }
    
return 0;
}

 

看了Discuss,基本上有两种方法:

1。用Stirling公式

公式和证明如下:

An important formula in applied mathematics as well as in probability is the Stirling's formula known as

 

/begin{displaymath}n! /sim /sqrt{2 /pi} /; n^{/displaystyle (n+ 1/2)} /;e^{/displaystyle-n} /end{displaymath}


 

where $/sim$ is used to indicate that the ratio of the two sides goes to 1 as n goes to $/infty$. In other words, we have

 

/begin{displaymath}/lim_{n /rightarrow /infty} /frac{n!}{/sqrt{2 /pi} /; n^{/displaystyle (n+ 1/2)}e^{/displaystyle-n}} = 1/end{displaymath}


 

or

 

/begin{displaymath}/lim_{n /rightarrow /infty} /frac{n!}{ n^{/displaystyle (n+ 1/2)}e^{/displaystyle-n}} = /sqrt{2 /pi}/;./end{displaymath}


 

 

Proof of the Stirling's Formula

First take the log of n! to get

 

/begin{displaymath}/log(n!) = /log (1) + /log(2) + /cdots + /log(n)/;./end{displaymath}


 

Since the log function is increasing on the interval $(0,/infty)$, we get

 

/begin{displaymath}/int_{n-1}^{n} /log(x) dx < /log(n) < /int_{n}^{n+1} /log(x) dx/end{displaymath}


 

for $n /geq 1$. Add the above inequalities, with $n=1,2,/cdots,N$, we get

 

/begin{displaymath}/int_{0}^{N} /log(x) dx < /log(N!) < /int_{1}^{N+1} /log(x) dx/end{displaymath}


 

Though the first integral is improper, it is easy to show that in fact it is convergent. Using the antiderivative of $/log(x)$ (being $x /log(x) -x$), we get

 

/begin{displaymath}n/log(n) - n < /log(n!) < (n+1)/log(n+1) - n/;./end{displaymath}


 

Next, set

 

/begin{displaymath}d_n = /log(n!) - /left(n + /frac{1}{2}/right) /log(n) + n/;./end{displaymath}


 

We have

 

/begin{displaymath}d_n - d_{n+1} = /left(n + /frac{1}{2}/right) /log/left(/frac{n+1}{n}/right) - 1/;./end{displaymath}


 

Easy algebraic manipulation gives

 

/begin{displaymath}/frac{n+1}{n} = /frac{1 + /displaystyle /frac{1}{2n+1}}{1 - /displaystyle /frac{1}{2n+1}}/;./end{displaymath}


 

Using the Taylor expansion

 

/begin{displaymath}/frac{1}{2} /log/left(/frac{1+t}{1-t}/right) = t + /frac{1}{3} t^3 + /frac{1}{5} t^5 + /cdots/end{displaymath}


 

for -1 < t < 1, we get

 

/begin{displaymath}d_n - d_{n+1} = /frac{1}{3} /frac{1}{(2n+1)^2} + /frac{1}{5} /frac{1}{(2n+1)^4} + /cdots/end{displaymath}


 

This implies

 

/begin{displaymath}0 < d_n - d_{n+1} < /frac{1}{3} /Bigg(/frac{1}{(2n+1)^2} + /frac{1}{(2n+1)^4} + /cdots/Bigg)/end{displaymath}


 

We recognize a geometric series. Therefore we have

 

/begin{displaymath}0 < d_n - d_{n+1} < /frac{1}{3} /frac{1}{(2n+1)^2 - 1} = /frac{1}{12} /left(/frac{1}{n} - /frac{1}{n+1}/right)/;./end{displaymath}


 

From this we get

1.
the sequence $/{d_n/}$ is decreasing;
2.
the sequence $/left/{d_n - /displaystyle /frac{1}{12n}/right/}$ is increasing.

This will imply that $/{d_n/}$ converges to a number C with

 

/begin{displaymath}/lim_{n /rightarrow /infty} d_n = /lim_{n /rightarrow /infty} d_n - /displaystyle /frac{1}{12n} = C /end{displaymath}


 

and that C > d1 - 1/12 = 1 - 1/12 = 11/12. Taking the exponential of dn, we get

 

/begin{displaymath}/lim_{n /rightarrow /infty}/frac{n!}{ n^{/displaystyle (n+ 1/2)}e^{/displaystyle-n}} = e^{C}/;./end{displaymath}


 

The final step in the proof if to show that $e^C = /sqrt{2/pi}$. This will be done via Wallis formula (and Wallis integrals). Indeed, recall the limit

 

/begin{displaymath}/lim_{n /rightarrow /infty} /frac{2.2.4.4.6.6/ldots(2n)(2n)}{1.1.3.3.5.5./ldots(2n-1)(2n-1)(2n+1)}/;= /frac{/pi}{2}/;./end{displaymath}


 

Rewriting this formula, we get

 

/begin{displaymath}/frac{2.4.6/ldots(2n)}{1.3.5./ldots(2n-1) /sqrt{2n}} /sim /sqrt{/frac{/pi}{2}}/end{displaymath}


 

Playing with the numbers, we get

 

/begin{displaymath}/frac{(2^n n!)^2}{(2n)!} /frac{1}{/sqrt{2n}} /sim /sqrt{/frac{/pi}{2}}/end{displaymath}


 

Using the above formula

 

/begin{displaymath}n! /sim n^{/displaystyle (n+ 1/2)}e^{/displaystyle-n} e^{C}/;./end{displaymath}


 

we get

 

/begin{displaymath}/frac{2^{2n} /Big(n^{2n+1} e^{-2n} e^{2C}/Big)}{(2n)^{(2n+1/2)} e^{-2n} e^C}/frac{1}{/sqrt{2n}} /sim /sqrt{/frac{/pi}{2}}/end{displaymath}


 

Easy algebra gives

 

/begin{displaymath}e^C /sim /sqrt{2/pi}/end{displaymath}


 

since we are dealing with constants, we get in fact $e^C = /sqrt{2/pi}$. This completes the proof of the Stirling's formula.

AC code:

#include <stdio.h>
#
include <math.h>

int n;
const double e = 2.7182818284590452354, pi = 3.141592653589793239;

double f( int a )
{
    
return log10sqrt2 * pi * a ) ) + a * log10( a / e );
}

int main()
{
    int cas
, ans;
    
double i, s;
    
    scanf( 
"%d", &cas );
    
    
while( cas-- )
    {
        scanf( 
"%d", &n );
        
if( n < 100000 )
        {
            
for( s=0, i=1; i<=n; i++ )
                s 
+= log10( i );
        }
        
else s = f( n );
        ans 
= (int)s;
        
if( ans <= s )
            ans
++;
        
        
printf"%d/n", ans );
    }
    
    
return 0;
}

 

2。用 位数=[ lg1+lg2+……lg(N-1)+lgN ] + 1。

数很大时,速度会慢,TLE。。

所以如上述AC代码,小于100000时,可以用这种方法,再大的话最好用Stiring公式。