数论-hdu3117题解

题目链接

题目大意:输出 Fibonacci 数列的第 n 项 an,如果 an 位数 ≤8 ,否则按格式“高四位…低四位”输出。

分析:注意点:题目给的 n 的范围是 [0, 108] ,直接使用递推的方式求 an 会超时,并且数值超出了表示范围(C++)。

首先Fibonacci 数列的 0~39 项的位数都是在 8 位以内的,如果不知道,可以观察测试用例,a39 对应 63245986 , a40 对应 1023…4155 。所以,对于 0~39 项,可以通过递推公式先打表。

然后,先考虑取出高四位。
Fibonacci 数列有如下的通项公式:
通项公式
对通项公式进行变换(两边取对数)得到下面的表达式:
在这里插入图片描述
以10为底取对数的好处在于,如果将大数用科学计数法的形式表示,例如 123456789123456789 。就可以写成 1.23456789123456789x1017 , 进一步可以写成 log10(1.23456789123456789)+17 这种小数加整数的形式,即 log10(123456781456789) = log10(1.23456789123456789)+17 ,如果想得到高四位,就是将 10log10(1234.56789123456789)向下取整即可,而 log10(1234.56789123456789) = log10(1.23456789123456789)+3 ,就和log10(123456789123456789) 建立了联系。按照这种思路,一个大数的高四位就容易得到了。

对于低四位,取模就可以,但是因为递推会超时,所以需要用到下面的性质:
在这里插入图片描述
这样就是矩阵快速幂+取模,在找到对应位置的值就可以了。

代码:

#include<bits/stdc++.h>
using namespace std;
typedef struct{
    int a[2][2];
}MATRIX;

const int mod = 10000;
MATRIX a, ans;
int k;
int f[40];

void init(){
    f[1] = 1;
    f[2] = 1;
    for(int i=3; i<40; i++){
        f[i] = f[i-1] + f[i-2];
    }
}

MATRIX mult(MATRIX a, MATRIX b){
    MATRIX tmp;
    for(int i=0; i<2; i++){
        for(int j=0; j<2; j++){
            tmp.a[i][j] = ((a.a[i][0]*b.a[0][j])%mod + (a.a[i][1]*b.a[1][j])%mod)%mod;
        }
    }
    return tmp;
}

MATRIX fastPow(MATRIX m, int n){
    MATRIX res;
    for(int i=0; i<2; i++){
        res.a[i][0] = res.a[i][1] = 0;
        res.a[i][i] = 1;
    }
    while(n){
        if(n&1) res = mult(res, a);
        a = mult(a, a);
        n >>= 1;
    }
    return res;
}

int head(int n){
    double t=-0.5*log10(5.0)+(double)n*log10((1+pow(5.0,0.5))/2);
    t=t-floor(t);  //获得小数部分
    double x=pow(10,t+3);  //还原
    return (int)floor(x);  //得到整数部分
}

int main(){
    init();
    while(~scanf("%d", &k)){
        if(k<40) printf("%d\n", f[k]);
        else{
            a.a[0][0] = 0;
            a.a[0][1] = a.a[1][0] = a.a[1][1] = 1;
            printf("%d...", head(k));
            ans = fastPow(a, k-1);
            printf("%04d\n", ans.a[1][1]);
        }
    }
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值