武大网赛预赛 Problem 1540 - D - Fibonacci

http://acm.whu.edu.cn/land/problem/detail?problem_id=1540


一道很简单的矩阵模版题,没有解出来真是打脸...

要你求斐波那契数列的每一项的三次方的前n项和。


解题思路:

要你求的是Sn 那么Sn = Sn-1 + Fx-1 ^ 3

(三个公式准备:

斐波那契数的Fx = Fx-1 + Fx-2

立方和公式 w^3 = (x + y)^3 = x^3 + 3x^2*y + 3x*y^2 + y^3;

平方和公式w^2 = (x + y)^2 = x^2 + 2*xy + y^2;)


构造一个矩阵,第一行的有5个项,分别是 Fn^3、Fn^2*Fn-1、Fn*Fn-1^2、Fn-1^3、Sn-1

Fn+1^3、Fn+1^2*Fn、Fn+1*Fn^2、Fn^3、Sn的情况。

然后就是利用三个公式凑出矩阵。

得到的矩阵就是

1 1 1 1 1

3 2 1 0 0

3 1 0 0 0

1 0 0 0 0

0 0 0 0 1)


然后看一下代码吧:


#include <cstdio>
#include <iostream>


using namespace std;

typedef long long ll;
const int maxn = 5;
const ll mod = 1000000007;

struct Mat{
    ll m[maxn][maxn];
    void initRight()
    {
        m[0][0] = m[0][1] = m[0][2] = m[0][3] = m[0][4] = 1;
        m[1][0] = 3, m[1][1] = 2, m[1][2] = 1;
        m[2][0] = 3, m[2][1] = 1;
        m[3][0] = 1;
        m[4][4] = 1;
    }
    void initLeft()
    {
        m[0][0] = m[0][1] = m[0][2] = m[0][3] = m[0][4] = 1;
    }
    Mat()
    {
        for(int i = 0; i < maxn; i++)
            for(int j = 0; j < maxn; j++)
                m[i][j] = 0;
    }
    void zero()
    {
        for(int i = 0; i < maxn; i++)
            for(int j = 0; j < maxn; j++)
                m[i][j] = 0;
    }
    void one()
    {
        for(int i = 0; i < maxn; i++)
            for(int j = 0; j < maxn; j++){
                m[i][j] = 0;
                if(i == j) m[i][j] = 1;
            }
    }
    Mat &operator = (const Mat &rhs)
    {
        for(int i = 0; i < maxn; i++)
            for(int j = 0; j < maxn; j++)
                m[i][j] = rhs.m[i][j];
        return *this;
    }
    Mat operator * (const Mat &rhs)
    {
        Mat mat;
        mat.zero();
        for(int i = 0; i < maxn; i++)
            for(int j = 0; j < maxn; j++)
                for(int k = 0; k < maxn; k++)
                    mat.m[i][j] = (mat.m[i][j] + m[i][k]*rhs.m[k][j])%mod;
        return mat;
    }
    Mat operator ^ (const int &mi)
    {
        Mat ret, a;
        int b = mi;
        ret.one();
        a = *this;
        while(b)
        {
            if(b & 1) ret = ret*a;
            a = a*a;
            b >>= 1;
        }
        return ret;
    }
};

int main()
{
//    freopen("data.in", "r", stdin);
    int n;
    Mat l, r, res;
    while(scanf("%d", &n) != EOF && n != 0)
    {
        l.zero();
        r.zero();
        l.initLeft();
        r.initRight();
        res = l * (r^(n-1));
        printf("%lld\n", res.m[0][4]);
    }
    return 0;
}






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值