Ⅰ 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;
}