POJ 1423. BigNumber (Time Limit Exceeded)

题目要求输入一个正整数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;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值