1. 程式人生 > >HDU 3117 Fibonacci Numbers

HDU 3117 Fibonacci Numbers

mes span name 公式 std 數值 can main for

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

題意:

  1. n < 40 時不會超過8位,直接打表輸出
  2. n ≥ 40 時:
    • 求一個數的前四位:
      • 推導公式:f(n) =\frac{1}{\sqrt{5}}[(\frac{1+\sqrt{5}}{2})^{n}(1-(\frac{1-\sqrt{5}}{1+\sqrt{5}})^{n}]
      • s = d.xxx * 10^{len - 4}
      • 兩邊取對數得 \log_{10}s = \log_{10}d.xxx + len -4
      • 再得d.xxxx=10^{\log_{10}s-len+4}
      • s =\frac{1}{ \sqrt{5}}*(\frac{1+\sqrt{5}}{2})^{n} (s後面的數值太小可以忽略)
      • len = {\log_{10}s + 1
    • 後四位:
    • 矩陣相乘:\begin{bmatrix}f(n)\\f(n-1) \end{bmatrix}=\begin{bmatrix}f(1)\\f(0) \end{bmatrix}*(\begin{bmatrix}1 & 1\\ 1 & 0\end{bmatrix})^{n-1}
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
typedef long long LL;

int fib[40
]; struct mat { int m[2][2]; }; int flag; int mod = 10000; void f() { fib[0] = 0; fib[1] = 1; for(int i = 2; ; i++) { fib[i] = fib[i-1] + fib[i-2]; if(fib[i] >= pow(10, 8)) { flag = i - 1; break; } } } int prev(LL n){ return pow(
10, (log10(1 / sqrt(5.0)) + n * log10((1 + sqrt(5.0)) / 2.0) - (int)(log10(1 / sqrt(5.0)) + n * log10((1 + sqrt(5.0)) / 2.0)) + 3)); } mat multiply(mat a, mat b) { mat c; for(int i = 0; i < 2; i++) { for(int j = 0; j < 2; j++) { c.m[i][j] = 0; for(int k = 0; k < 2; k++) { c.m[i][j] += (a.m[i][k] * b.m[k][j]) % mod; c.m[i][j] %= 10000; } } } return c; } mat p = {1, 1, 1, 0}; mat q = {1, 0, 0, 1}; mat quickPower(LL n) { mat m = p, b = q; while(n) { if(n & 1) { b = multiply(b, m); } n >>= 1; m = multiply(m, m); } return b; } int main() { LL n; f(); while (~scanf("%lld", &n)) { if(n <= flag) printf("%d\n", fib[n]); else { printf("%d...%04d\n", prev(n), quickPower(n).m[0][1]); } } return 0; }

HDU 3117 Fibonacci Numbers