hdu3117
求[0,1e8]的F(n)的前后4位。
输入:
35 36 37 38 39 40 64 65输出:
9227465 14930352 24157817 39088169 63245986 1023...4155 1061...7723 1716...7565
1.斐波那契数列前4位的计算
通项公式 f[n]=(1/sqrt(5)) * { [(1 + sqrt(5)) / 2] ^ n - [(1 - sqrt(5)) / 2]^ n }
减号后面的部分,底数小于1,当n增大时,非常小,可以忽略。
F(n),对10取对数,得double lg = -0.5 * log10(5.0) + n * log10(gold);
直接再对10取幂貌似超时。
因为10对0.b次方等于10对a.b次方向右移a位,数字不变,所以可以
lg -= (int)lg;
double fn =pow(10,lg);
2.斐波那契数列对mod取余的计算
f(1)=1,f(2)=2,f(n)=f(n-1)+f(n-2)(n>=3)
用矩阵表示为:
可用矩阵快速幂取模求解。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
const int maxn = 40;
const double gold = (1 + sqrt(5.0)) / 2;
long long f[maxn] = {0,1};
struct martrix{
int a[2][2] = {{1,0},{0,1}};
};
martrix multiply(martrix &a,martrix &b,int n)
{
martrix res;
memset(res.a,0,sizeof(res.a));
for (int i = 0; i < n; i ++) {
for (int j = 0; j < n; j ++) {
for (int k = 0; k < n; k ++) {
res.a[i][j] += a.a[i][k] * b.a[k][j];
}
res.a[i][j] %= 10000;
}
}
return res;
}
void prefix(int n)
{
double lg = -0.5 * log10(5.0) + n * log10(gold);
lg -= (int)lg;
double fn = pow(10,lg);
while(fn < 1000) fn *= 10;
printf("%d...",(int)fn);
}
void suffix(int k)
{
martrix res,q;
q.a[0][1] = 1;q.a[1][0] = 1;q.a[1][1] = 0;
while(k)
{
if (k & 1) {
res = multiply(res, q, 2);
}
k >>= 1;
q = multiply(q, q, 2);
}
int fn = res.a[0][0] + res.a[0][1];
printf("%04d\n",fn % 10000);
}
int main()
{
for(int i = 2;i < maxn;i ++) f[i] = f[i - 1] + f[i - 2];
int n;
while(scanf("%d",&n) != EOF)
{
if (n < maxn) {
printf("%lld\n",f[n]);
}
else {
prefix(n);
suffix(n - 2);
}
}
return 0;
}