HDU 2842 矩阵快速幂(模板)

HDU 2842 矩阵快速幂

题目

链接
在这里插入图片描述
根据题意推出公式: F n = F n − 1 + 2 ∗ F n − 2 + 1 F_n = F_{n-1} + 2*F_{n-2} +1 Fn=Fn1+2Fn2+1,然后利用矩阵快速幂。
( F n − 1 F n − 2 1 ) ∗ ( 1 1 0 2 0 0 1 0 1 ) = ( F n F n − 1 1 ) \begin{pmatrix}F_{n-1}&F_{n-2}&1\\\end{pmatrix} * \begin{pmatrix}1&1&0\\2&0&0\\1&0&1\end{pmatrix} = \begin{pmatrix}F_n&F_{n-1}&1\\\end{pmatrix} (Fn1Fn21)121100001=(FnFn11)
由上面公式可知,初始矩阵为 ( F n − 1 F n − 2 1 ) \begin{pmatrix}F_{n-1}&F_{n-2}&1\\\end{pmatrix} (Fn1Fn21),幂次矩阵为 ( 1 1 0 2 0 0 1 0 1 ) \begin{pmatrix}1&1&0\\2&0&0\\1&0&1\end{pmatrix} 121100001,可以在 O ( l o g n ) O(logn) O(logn)级别的复杂度求出 F n F_n Fn.
代码:

#include<cstdio>
#include<algorithm>
#include<vector>
#include<cstring>
#include<cmath>
using namespace std;
const int mod = 200907;
typedef long long LL;

const int m_size = 3;
const int m_max = 5;
struct node
{
    LL d[m_max][m_max];
};
node matrixm(node a, node b)
{
    node ans;
    for(int i = 0; i < m_max; i++)
        for(int j = 0; j < m_max; j++)
            ans.d[i][j] = 0;
    for(int j = 0; j <m_size; j++)
        for(int k = 0; k <m_size; k++)
            ans.d[0][j] = (ans.d[0][j]+a.d[0][k]*b.d[k][j])%mod;
    return ans;
}
node matrixw(node a, node b)
{
    node ans;
    for(int i = 0; i < m_max; i++)
        for(int j = 0; j < m_max; j++)
            ans.d[i][j] = 0;
    for(int i = 0; i < m_size; i++)
        for(int j = 0; j <m_size; j++)
            for(int k = 0; k <m_size; k++)
                ans.d[i][j] = (ans.d[i][j]+a.d[k][j]*b.d[i][k])%mod;
    return ans;
}

void initres(node &res)
{
    for(int i = 0; i < m_max; i++)
        for(int j = 0; j < m_max; j++)
            res.d[i][j] = 0;
    res.d[0][0] = 1;res.d[0][1] = 1;res.d[0][2] = 0;
    res.d[1][0] = 2;res.d[1][1] = 0;res.d[1][2] = 0;
    res.d[2][0] = 1;res.d[2][1] = 0;res.d[2][2] = 1;
    return ;
}
void initans(node &ans)
{
    for(int i = 0; i < m_max; i++)
        for(int j = 0; j < m_max; j++)
            ans.d[i][j] = 0;
    ans.d[0][0] = 2;ans.d[0][1] = 1;ans.d[0][2] = 1;
    return ;
}

node ppow(node an, node re,LL k)
{
    node ans = an;
    node res = re;
    while(k)
    {
        if(k&1)
            ans = matrixm(ans, res);
        res = matrixw(res, res);
        k >>= 1;
    }
    return ans;
}
int main()
{
    LL n;
    node ans, res;
    initans(ans);
    initres(res);
    while(scanf("%lld", &n)&&n)
    {
        if(n==1)
        {
            printf("1\n");
        }
        else if(n==2)
        {
            printf("2\n");
        }
        else
        {
            node fans = ppow(ans,res,n-2);
            printf("%lld\n", fans.d[0][0]);
        }

    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值