首页 > 代码库 > HDU 3117 Fibonacci Numbers 数学

HDU 3117 Fibonacci Numbers 数学

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

fib是有一个数学公式的。

技术分享

这里的是标准的fib公式

那么fib = 1 / sqrt(5) * ((1 + sqrt(5) / 2) ^ n - ((1 - sqrt(5)) / 2)^n) = 1 / sqrt(5) * (A^n - B^n)

那么,求后4位可以直接矩阵快速幂。

不能用上面公式的快速幂取模,因为存在精度误差。

然后求前4位的话,就是一个套路公式了。

在上一篇博客。http://www.cnblogs.com/liuweimingcprogram/p/6583154.html

这里因为后面的B很小,所以可以忽略。如果不忽略的话,就没办法做了。

比如你取A得前4位,减去B的前4位,那肯定错。比如123456789的前4位是1234,而1234的前4位又是1234,那么相减就等于0了。不过这里B的小数,前4位也是0.

 

然后还要除以sqrt(5),这个时候就需要你保留前5位,除以sqrt(5)后,再保留4位。

不然的话,比如你取了前4位是1234,除以sqrt(5),只剩下3位了。

 

技术分享
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <assert.h>
#define IOS ios::sync_with_stdio(false)
using namespace std;
#define inf (0x3f3f3f3f)
typedef long long int LL;


#include <iostream>
#include <sstream>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <string>
#include <bitset>
const int maxn = 4;
struct Matrix {
    LL a[maxn][maxn];
    int row;
    int col;
};
struct Matrix matrix_mul  (struct Matrix a, struct Matrix b, int MOD) {  //求解矩阵a*b%MOD
    struct Matrix c = {0};  //这个要多次用到,栈分配问题,maxn不能开太大,
    //LL的时候更加是,空间是maxn*maxn的,这样时间用得很多,4和5相差300ms
    c.row = a.row; //行等于第一个矩阵的行
    c.col = b.col; //列等于第二个矩阵的列
    for (int i = 1; i <= a.row; i++) { //枚举第一个矩阵的行
        for (int j = 1; j <= b.col; j++) { //枚举第二个矩阵的列,其实和上面数值一样
            for (int k = 1; k <= b.row; k++) { //b中的一列中,有“行”个元素 notice
                c.a[i][j] += a.a[i][k] * b.a[k][j];  //这里不及时取模,又有可能错!HDU 4565
            }
            c.a[i][j] = (c.a[i][j] + MOD) % MOD; //如果怕出现了负数取模的话。可以这样做
        }
    }
    return c;
}
struct Matrix quick_matrix_pow(struct Matrix ans, struct Matrix base, int n, int MOD) {
//求解a*b^n%MOD
    while (n) {
        if (n & 1) {
            ans = matrix_mul(ans, base, MOD);//传数组不能乱传,不满足交换律
        }
        n >>= 1;
        base = matrix_mul(base, base, MOD);
    }
    return ans;
}
LL fib[222];
void init() {
    fib[0] = 0;
    fib[1] = 1;
    for (int i = 2; i <= 40; ++i) {
        fib[i] = fib[i - 1] + fib[i - 2];
    }
}
int n;
int calc(double a, LL b, int k) { //a^b的前k + 1位
    double res = b * log10(a * 1.0) - (LL)(b * log10(a * 1.0)); //获得小数部分
    return (int)(pow(10.0, k + res) / sqrt(5.0));
}

int getMost() {
    double a = (1 + sqrt(5.0)) / 2;
    int res = calc(a, n, 4);
    while (res >= 10000) res /= 10;
    return res;
}
int getLow() {
    struct Matrix t1 = {0};
    t1.row = 1, t1.col = 2;
    t1.a[1][1] = 1, t1.a[1][2] = 0;

    struct Matrix t2 = {0};
    t2.row = t2.col = 2;
    t2.a[1][1] = t2.a[1][2] = 1;
    t2.a[2][1] = 1, t2.a[2][2] = 0;

    struct Matrix res = quick_matrix_pow(t1, t2, n - 1, 10000);
    return res.a[1][1];
}
void work() {
    if (n <= 39) {
        cout << fib[n] << endl;
        return;
    }
    int most = getMost();
    int low = getLow();
    printf("%04d...%04d\n", most, low);
}
int main() {
#ifdef local
    freopen("data.txt", "r", stdin);
//    freopen("data.txt", "w", stdout);
#endif
    init();
    while (cin >> n) work();
    return 0;
}
View Code

 

HDU 3117 Fibonacci Numbers 数学