题目要求输入一个正整数N(1<= N <= 10'000'000),然后输出N!的位数。
N虽然没有超出int型的表示范围,但N!会远远大于。所以我想到的手工模拟的办法。但是,这个问题的规模很大,用手工模拟计算效率太低,很难在规定的时间内计算出来。
虽然看起来问题的规模是线性的,只需要算一遍N的阶乘就可以。但是,每次手工模拟都要遍历一次factorial数组,当N = 100'000的时候,factorial数组的长度是456'574,在笔记本(i3, 4G)上耗时约为274.3s。
根据题目所示,可以得到递推公式:
整理后得到递推公式:
,其中floor()表示向下取整。
最后整理得到:
好吧,到这能力有限,分析不了了,希望有人能指教,如果存在错误也同样欢迎指出
错误的实现如下:
#include <stdio.h>
#include <stdlib.h>
#define CHUNK 10000 //the size of every increasement of memory
#define INIT_SIZE 100000
/*
* the simulation of multiplication by head
* array is used to store factorial, refference of a pointer
* n is the input number
* lng is the length of factorial
*/
int calcFactorial(short int* &array, int n, int lng);
int SIZE; //the current maximum size of the array
int main()
{
int testCase, num;
int length; //the length of factorial
scanf("%d", &testCase);
while(testCase--)
{
scanf("%d", &num);
//initalize the array to store factorial
short int* fact = (short int*)calloc(INIT_SIZE, sizeof(short int));
SIZE = INIT_SIZE;
//initalize the arguments of fact(the array)
fact[0] = 1;
length = 1;
//calculate factorial
for(; num > 1; num--)
{
//simulate every multiplication, and update the length of fact
length = calcFactorial(fact, num, length);
}
free(fact);
//print answer
printf("%d\n", length);
}
return 0;
}
int calcFactorial(short int* &array, int n, int lng)
{
int cur = 0;
for(int i = 0; i < lng; i++)
{
//check for enough memory
if(lng + CHUNK > SIZE)
{
if(realloc(array, (SIZE + CHUNK) * sizeof(short int)) == NULL)
{
exit(1);
}
SIZE += CHUNK;
}
//simulate multiplication
cur += array[i] * n;
array[i] = cur % 10;
cur /= 10;
}
//handle rest part of the product and update length of array
while(cur > 0)
{
int i = lng;
array[i] = cur % 10;
cur /= 10;
lng++;
}
return lng;
}
在Online Judge上测试没有通过,才反应过来。然后就想起了组合数学中的stirling公式(维基百科):
[摘自:斯特灵公式--维基百科]
利用对数公式将上式整理为:
求数字N的位数:(int)lg(N) + 1;
代码实现如下(这次的AC了):
/*
* BigNumber_stirling.c
*
* Created on: 2013-7-31 21:59
* Author: KG-LiGuang
*/
#include <math.h>
#include <stdio.h>
#define PI 3.1415926
#define e 2.718281828459045
int calcDigitNumOf(int n);
int main()
{
int testCase, num;
scanf("%d", &testCase);
while(testCase--)
{
scanf("%d", &num);
int lng = calcDigitNumOf(num);
printf("%d\n", lng);
}
return 0;
}
int calcDigitNumOf(int n)
{
if(n > 0)
return (int)(log10(2 * n * PI) / 2 + n * log10(n / e)) + 1;
else
return 1;
}