WOJ1540 Fibonacci(数学推导,矩阵快速幂)

来源:互联网 发布:linux目录详解 编辑:程序博客网 时间:2024/06/05 03:50

题目戳这里
题意:求斐波那契数列的前n项立方和,1<=n<=10^9,例如前3项为1^3+1^3+2^3=10.
思路:鉴于n如此大的规模,很明显不能直接求,所以需要用到矩阵快速幂的改进版
我们知道斐波那契数列第n项可以表示为矩阵
1 1
1 0
的n次方,那前n项立方和能否用矩阵的n次方来表示呢?我们可以递推来考虑:
1.如果是要求前n项和sum(f(n)),展开后我们发现:
sum(fn) = fn + fn-1 + fn-2 +…+ f2 + f1 = (fn-1+fn-2) + (fn-2+fn-3) +…+(f2+f1) + f2 + f1 = sum(fn-1) + sum(fn-2) + f2//f2就是1啦

于是我们可以得到矩阵:
0 1 0
1 1 0
0 1 0
斐波那契数列前n(n>=3)项和不就等于该矩阵的(n-1)次方后第3行之和吗?第三行的三个数分别代表了sum(fn-1),sum(fn-2),f2.
2.如果是前n项平方和,同1展开后得到矩阵
0 1 0 0
1 1 2 0
0 1 1 0
0 1 0 1
第4行之和即为sum((fn)^2)
3.便是本题所求,展开式过长在此不予赘述,同理得到矩阵:
0 1 0 0 0
1 1 3 3 0
0 1 0 1 0
0 1 1 2 0
0 1 0 0 1
再运用快速幂即可ac。

代码如下:

/** @author Novicer* language : C++/C*/#include<iostream>#include<sstream>#include<fstream>#include<vector>#include<list>#include<deque>#include<queue>#include<stack>#include<map>#include<set>#include<bitset>#include<algorithm>#include<cstdio>#include<cstdlib>#include<cstring>#include<cctype>#include<cmath>#include<ctime>#include<iomanip>using namespace std;const double eps(1e-8);typedef long long lint;const lint Mod = 1000000007;struct matrix{    lint m[5][5];};matrix multi(matrix a , matrix b){    matrix tmp;    for(int i = 0 ; i < 5 ; i++){        for(int j = 0 ; j < 5 ; j++){            tmp.m[i][j] = 0;            for(int k = 0 ; k < 5 ; k++){                tmp.m[i][j] = (tmp.m[i][j] + (a.m[i][k] * b.m[k][j])% Mod)%Mod;            }        }    }    return tmp;}matrix fast_mod(matrix base,lint n){    matrix ans;    for(int i = 0 ; i < 5 ; i++){        for(int j = 0 ; j < 5 ; j ++){            ans.m[i][j] = (i == j)? 1:0;        }    }    while(n){        if(n&1){            ans = multi(ans,base);        }        base = multi(base,base);        n >>= 1;    }    return ans;}int main(){    int n;    while(cin >> n){        if(n == 0) break;        lint sum = 0;        matrix base;        if(n == 1) sum = 1;        else if(n == 2) sum = 2;        else{            for(int i = 0 ; i < 5 ; i++){                for(int j = 0 ; j < 5 ; j++){                    base.m[i][j] = 0;                }            }            base.m[0][1] = 1;            base.m[1][0] = 1;            base.m[1][1] = 1;            base.m[1][2] = 3;            base.m[1][3] = 3;            base.m[2][1] = 1;            base.m[2][3] = 1;            base.m[3][1] = 1;            base.m[3][2] = 1;            base.m[3][3] = 2;            base.m[4][1] = 1;            base.m[4][4] = 1;            for(int i = 0 ; i < 5 ; i++){                sum = (sum + fast_mod(base,n - 1).m[4][i]) % Mod;            }        }        cout << sum << endl;    }    return 0;}
0 0