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

fib是有一个数学公式的。

HDU 3117 Fibonacci Numbers 数学_#define

这里的是标准的fib公式

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

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

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

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


这里因为后面的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