求大数最左边的某几位数

 http://acm.hdu.edu.cn/showproblem.php?pid=1715

HDOJ里1715 大斐波数。求第N(1<=N<=1000)位斐波那契数,这里只要定义一个二位数组a[1010][3000],然后运用大数运算,用打表的方法把1~1010位大数存到二维数组中,然后再调用。(这里有位N最大是1000,所以定义二维数组不会超__int64)。下边是自己的代码http://blog.csdn.net/simoncoder/article/details/38303585

http://acm.hdu.edu.cn/showproblem.php?pid=1250

HDOJ里1250 Hat's Fibonacci。求第N位斐波那契数,这里N没有作限制,但限制了长度不超过2005,通过测试,第7100位斐波那契数刚超2005位,定义二维数组a[7100][2008],但提交以后超内存,虽然没有超__int64。然后才改计算法,改为四位一相加,然后存到数组的二维的一个数组名下,这样成功AC。下边是自己的代码http://blog.csdn.net/simoncoder/article/details/38375607

还有一类题,求第N位斐波那契数的前n位数,或者求一个大数的前n位数。如HDOJ 1568 Fibonacci,HDOJ 1060 Leftmost Digit。因为N会很大(如1568中(0<N<1000000000))或者大数很大,这时做1568时就不能用二维数组了,因为如果用二维数组,第一维已经到了__int64的极限,再加第二位肯定超。


下面说第种情况的算法:

在这之前先看几个函数。函数的头文件均为#include<math.h>.

1.求log10(X),函数原型double log10(double X);

2.求X^Y的值,函数原型double pow(double X,double Y);

3.求√X,函数原型double sqrt(double X);


说的问题是,如何求一个大数(超出__int64范围,不能用__int64存放)的最左边一位或几位数字。

 给定一个大数num,num还可以写成num=x*10^n,这里x为小数且1<x<10。

1.对num=x*10^n两边同时取以10为底的对数,log10(num)=log10(x*10^n)=log10(x)+log10(10^n),进一步化解,log10(num)=log10(x)+n.

如果要求num的第一位数,只要求出x,然后对x取整,即(__int64)x即为所求。(如果要求前几位数,在最后对x取整时稍作调整即可,后面会说)。

2.现在要求x,所以要做适当的变形,1.中log10(num)=log10(x)+n可变为log10(x)=log10(num)-n,再变一下得到

x=10^(log10(num)-n)。

先来看n,由1.可得 log10(num)=log10(x)+n,而num=x*10^n,所以1<x<10,得0<log10(x)<1,所以log10(x)是

log10(num)的小数部分,n是log10(num)的整数部分,所以n=(__int64)log10(num)。

所以2.中x=10^(log10(num)-n)=10(log10(num)-(__int64)log10(num)).然后再对x取整即为num的第一位数,(__int64)x。

当要求num的前m位数时,在最后对x取整数时要先乘10^(m-1),再取整,即(__int64)(x*10^(m-1))


下面是杭电的两个题,还有我自己的代码

HDOJ1060 Leftmost Digit http://acm.hdu.edu.cn/showproblem.php?pid=1060

#include<stdio.h>
#include<math.h>
__int64 N;
int main()
{
	int T;
	double t;
	scanf("%d",&T);
	while(T--)
	{
		scanf("%I64d",&N);
		t=N*log10((double)N);
		//printf("%lf#\n",t);
		t-=(__int64)(t);
		//printf("%lf$\n",t);
		printf("%I64d\n",(__int64)(pow((double)10,t)));
	}
	return 0;
}

HDOJ1568 Fibonacci http://acm.hdu.edu.cn/showproblem.php?pid=1568

这个题需要用到斐波那契数列第n项的通项公式

因为当n>=20时,才会用到通项公式计算,而n>=20时|((1-5^0.5)/2)^n|<1*10^-5,可以忽略,通项公式可以写成an=(((1+5^0.5)/2)^n)/5^0.5。

#include<stdio.h>
#include<math.h>
int main()
{
	int i,a[20];
	for(i=2,a[0]=0,a[1]=1;i<20;i++)
	a[i]=a[i-1]+a[i-2];
	__int64 N;
	double t;
	while(scanf("%I64d",&N)!=EOF)
	{
		if(N<20)
		printf("%d\n",a[N]);
		else
		{
			t=N*log10((1+pow((double)5,0.5))*0.5)-log10(pow((double)5,0.5));
			//printf("%lf\n",t);
			t-=(__int64)t;
			//printf("%lf\n",t);
			printf("%I64d\n",(__int64)(pow((double)10,t)*1000));
		}
	}
    return 0;
}




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值