题目大意:输入一个n,求n的斐波那契数值的前四位和后四位,如果位数小于等于8 位,则全部输出。
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3117点击打开链接
解题思路:后四位可用矩阵快速幂求出,而前四位则可用公式求出,借鉴了某大神的博客http://blog.sina.com.cn/s/blog_9bf748f301019q3t.html
求解前四位的方法:斐波那契数列的通项公式如下:, 改变通项的形式:
F(n)=(1/√5)*[((1+√5)/2)^n-((1-√5)/2)^n]=(1/√5)*[((1+√5)/2)^n*(1-((1-√5)/(1+√5))^n)]
即F(n)的各项可以由以上通项公式求得,而不是采用迭代。
对变化后的通项取对数,则得下式:
log10(F(n))=-0.5*log10(5.0)+((double)n)*log(f)/log(10.0)+log10(1-((1-√5)/(1+√5))^n)
其中第三部分非常小,当n很大时趋近于0,可以忽略掉。
因此,采用下式即可:
temp=-0.5*log(5.0)/log(10.0)+((double)n)*log(s)/log(10.0);
求解后四位的方法:矩阵快速幂
斐波那契数列的矩阵表示形式为:
代码如下:
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
#define N 2
int M, n;
typedef struct
{
int m[2][2];
}Matrax;
Matrax multi(Matrax a, Matrax b)
{
Matrax c;
for(int i = 0; i < N; i ++)
for(int j = 0; j < N; j ++)
{
c.m[i][j] = 0;
for(int k = 0; k < N; k ++)
{
c.m[i][j] = c.m[i][j] + a.m[i][k] * b.m[k][j] % M;
}
c.m[i][j] %= M;
}
return c;
}
int power(Matrax& p)
{
if(n<=1) return n;
Matrax ans;
ans.m[0][0] = 1;ans.m[0][1] = 0;
ans.m[1][0] = 0;ans.m[1][1] = 1;
/* n --;
while(n)
{
if(n % 2)
{
ans = multi(ans, p);
}
n /= 2;
p = multi(p, p);
}*/
n --;
while(n)
{
if(n & 1)
{
ans = multi(ans, p);
n--;
}
else{
n= n/2;
p= multi(p , p);
}
}
return ans.m[0][0] % M;
}
int main()
{
Matrax p;
while(~scanf("%d", &n))
{
M = 1e4;
p.m[0][0] = 1; p.m[0][1] = 1;
p.m[1][0] = 1; p.m[1][1] = 0;
if(n <= 39)
{
M = 1e9;
printf("%d\n",power(p));
}
else
{
double temp;
double s = (sqrt(5.0) + 1.0) / 2.0;
temp = -0.5 * log(5.0) / log(10.0) + ((double)n) * log(s)/log(10.0);
temp = temp -floor(temp);
temp = pow(10.0, temp);
while(temp < 1000) temp = temp * 10;
printf("%04d...%04d\n", (int)temp, power(p));
}
}
return 0;
}
输出的时候需要注意一下,用%04d ,而不能用%4d,%04d在位数不足四位的情况下,前面自动补零,而%4d就只是右对齐。
P.S. hdu3117要是过掉了的话, hdu1568 那就轻松加愉快啦啦啦~~~