佳佳的斐波那契

佳佳的斐波那契

题目描述

在这里插入图片描述


核心思路

由题目可知, S n = f 1 + f 2 + ⋯ + f n S_n=f_1+f_2+\cdots +f_n Sn=f1+f2++fn T n = f 1 + 2 f 2 + ⋯ + ( n − 1 ) f n − 1 + n f n T_n=f_1+2f_2+\cdots +(n-1)f_{n-1}+nf_n Tn=f1+2f2++(n1)fn1+nfn

我们设 p n = n S n − T n p_n=nS_n-T_n pn=nSnTn,则会有 p n = ( n − 1 ) f 1 + ( n − 2 ) f 2 + ⋯ + 1 f n − 1 + 0 f n p_n=(n-1)f_1+(n-2)f_2+\cdots +1f_{n-1}+0f_n pn=(n1)f1+(n2)f2++1fn1+0fn,记为【1】式

我们设 p n + 1 = ( n + 1 ) S n + 1 − T n + 1 = n f 1 + ( n − 1 ) f 2 + ⋯ + 2 f n − 1 + 1 f n p_{n+1}=(n+1)S_{n+1}-T_{n+1}=nf_1+(n-1)f_2+\cdots +2f_{n-1}+1f_n pn+1=(n+1)Sn+1Tn+1=nf1+(n1)f2++2fn1+1fn,记为【2】式

用【2】-【1】,可以得到:

p n + 1 − p n = f 1 + f 2 + ⋯ + f n − 1 + f n = S n p_{n+1}-p_n=f_1+f_2+\cdots +f_{n-1}+f_n=S_n pn+1pn=f1+f2++fn1+fn=Sn,也就是有 p n + 1 − p n = S n p_{n+1}-p_n=S_n pn+1pn=Sn

由于 p n = n S n − T n p_n=nS_n-T_n pn=nSnTn,因此如果我们想要求出 T n T_n Tn,则需要先求出 p n p_n pn S n S_n Sn

我们设 F n F_n Fn= [ f n f n + 1 S n p n ] \left [\begin {matrix} f_n & f_{n+1} & S_n & p_n\end{matrix} \right] [fnfn+1Snpn],设 F n + 1 = [ f n + 1 f n + 2 S n + 1 p n + 1 ] F_{n+1}=\left [\begin {matrix} f_{n+1} & f_{n+2} & S_{n+1} & p_{n+1}\end{matrix} \right] Fn+1=[fn+1fn+2Sn+1pn+1]

构造一个矩阵 A = [ 0 1 0 0 1 1 1 0 0 0 1 1 0 0 0 1 ] A=\left [\begin {matrix} 0 & 1 & 0 &0\\ 1& 1& 1& 0\\ 0&0&1&1\\ 0&0&0&1\end{matrix} \right] A=0100110001100011,那么就会有 F n × A = F n + 1 F_n\times A=F_{n+1} Fn×A=Fn+1

通过递推可知, F n = F 1 × A n − 1 F_n=F_1\times A^{n-1} Fn=F1×An1,其中 F 1 F_1 F1是边界, F 1 F_1 F1= [ f 1 f 2 S 1 p 1 ] \left [\begin {matrix} f_1 & f_{2} & S_1 & p_1\end{matrix} \right] [f1f2S1p1] f 1 = 1 , f 2 = 1 f_1=1,f_2=1 f1=1,f2=1,而 S 1 = f 1 = 1 S_1=f_1=1 S1=f1=1,由于 p n = n S n − T n p_n=nS_n-T_n pn=nSnTn,那么 p 1 = S 1 − T 1 p_1=S_1-T_1 p1=S1T1,而 T 1 = f 1 = 1 T_1=f_1=1 T1=f1=1,所以 p 1 = 1 − 1 = 0 p_1=1-1=0 p1=11=0

所以,我们只需要用矩阵快速幂求出 A n − 1 A^{n-1} An1就好了。然后 T n = n S n − p n T_n=nS_n-p_n Tn=nSnpn,即可求得结果 T n T_n Tn


代码

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=4;
typedef long long LL;
int n,m;
void mul(int a[][N],int b[][N],int c[][N])
{
    int tmp[N][N]={0};
    for(int i=0;i<N;i++)
    {
        for(int j=0;j<N;j++)
        {
            for(int k=0;k<N;k++)
            {
                tmp[i][j]=(tmp[i][j]+(LL)a[i][k]*b[k][j])%m;
            }
        }
    }
    memcpy(c,tmp,sizeof tmp);
}
int main()
{
    scanf("%d%d",&n,&m);
    //本来边界F1={1,1,1,0},但是我们这里为了只写一个mul函数,所以把它改造成了N*N的矩阵
    //这样就相当于只处理了两个矩阵相乘,方便了计算
    int F[N][N]={
            {1,1,1,0},
            {0,0,0,0},
            {0,0,0,0},
            {0,0,0,0}
    };
    //构造矩阵A
    int a[N][N]={
            {0,1,0,0},
            {1,1,1,0},
            {0,0,1,1},
            {0,0,0,1}
    };
    int b=n-1;
    while(b)
    {
        if(b&1)
            mul(F,a,F); //相当于res=res*a
        mul(a,a,a);     //相当于a=a*a
        b>>=1;
    }
    //注意这里有可能两个数相减结果会为负数,如果取模得到的结果就是负的
    //为了得到正的模数,可以采用(x%m+m)%m的方法
    printf("%d\n",(((LL)n * F[0][2] - F[0][3]) % m + m) % m);
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

卷心菜不卷Iris

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值