HDU 3117 Fibonacci Numbers 数学
Posted stupid_one
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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; }
以上是关于HDU 3117 Fibonacci Numbers 数学的主要内容,如果未能解决你的问题,请参考以下文章
HDU3117-Fibonacci Numbers(矩阵高速幂+log)