矩阵快速幂 - 佳佳的斐波那契 - AcWing 1304

矩阵快速幂 - 佳佳的斐波那契 - AcWing 1304

佳佳对数学,尤其对数列十分感兴趣。

在研究完 Fibonacci 数列后,他创造出许多稀奇古怪的数列。

例如用 S(n) 表示 Fibonacci 前 n 项和 mod m 的值,

即 S ( n ) = ( F 1 + F 2 + … + F n ) m o d   m , 其 中 F 1 = F 2 = 1 , F i = F i − 1 + F i − 2 。 即 S(n)=(F_1+F_2+…+F_n)mod\ m,其中 F_1=F_2=1,F_i=F_{i−1}+F_{i−2}。 S(n)=(F1+F2++Fn)mod mF1=F2=1,Fi=Fi1+Fi2

可这对佳佳来说还是小菜一碟。

终于,她找到了一个自己解决不了的问题。

用 T ( n ) = ( F 1 + 2 F 2 + 3 F 3 + … + n F n ) m o d   m 表 示 F i b o n a c c i 数 列 前 n 项 变 形 后 的 和 m o d   m 的 值 。 用 T(n)=(F_1+2F_2+3F_3+…+nF_n)mod\ m 表示 Fibonacci 数列前 n 项变形后的和 mod\ m 的值。 T(n)=(F1+2F2+3F3++nFn)mod mFibonaccinmod m

现在佳佳告诉你了一个 n 和 m,请求出 T(n) 的值。

输入格式

共一行,包含两个整数 n 和 m。

输出格式

共一行,输出 T(n) 的值。

数据范围

1 ≤ n , m ≤ 2 31 − 1 1≤n,m≤2^{31}−1 1n,m2311

输入样例:

5 5

输出样例:

1

样例解释

T ( 5 ) = ( 1 + 2 × 1 + 3 × 2 + 4 × 3 + 5 × 5 ) m o d   5 = 1 T(5)=(1+2×1+3×2+4×3+5×5)mod\ 5=1 T(5)=(1+2×1+3×2+4×3+5×5)mod 5=1


分析:

求 S n : 求S_n: Sn矩阵快速幂 - 斐波那契前 n 项和 - AcWing 1303

已 知 S n 与 F n 的 关 系 , 现 要 将 T n 与 S n 和 F n 建 立 关 系 , 通 过 已 知 来 求 未 知 , 已知S_n与F_n的关系,现要将T_n与S_n和F_n建立关系,通过已知来求未知, SnFnTnSnFn

观 察 发 现 , T n 相 比 于 S n , 关 于 n 的 次 数 要 高 一 次 , 观察发现,T_n相比于S_n,关于n的次数要高一次, TnSnn

我 们 先 给 S n 升 幂 , 乘 一 个 n , 我们先给S_n升幂,乘一个n, Snn

{ T n = F 1 + 2 F 2 + 3 F 3 + … + n F n n S ( n ) = n F 1 + n F 2 + n F 3 + … + n F n \begin{cases}T_n=F_1+2F_2+3F_3+…+nF_n\\ \\nS(n)=nF_1+nF_2+nF_3+…+nF_n\end{cases} Tn=F1+2F2+3F3++nFnnS(n)=nF1+nF2+nF3++nFn

记 P n = n S n − T n = ( n − 1 ) F 1 + ( n − 2 ) F 2 + ( n − 3 ) F 3 + . . . + F n − 1   ① 记P_n=nS_n-T_n=(n-1)F_1+(n-2)F_2+(n-3)F_3+...+F_{n-1}\qquad\qquad\ ① Pn=nSnTn=(n1)F1+(n2)F2+(n3)F3+...+Fn1 

则 P n + 1 = ( n + 1 ) S n + 1 − T n + 1 = n F 1 + ( n − 1 ) F 2 + ( n − 2 ) F 3 + . . . + F n    ② 则P_{n+1}= (n+1)S_{n+1}-T_{n+1}=nF_1+(n-1)F_2+(n-2)F_3+...+F_n\quad\quad\ \ ② Pn+1=(n+1)Sn+1Tn+1=nF1+(n1)F2+(n2)F3+...+Fn  

② − ① 得 P n + 1 − P n = F 1 + F 2 + . . . + F n = S n , 即 P n + 1 = P n + S n ②-①得P_{n+1}-P_n=F_1+F_2+...+F_n=S_n,即P_{n+1}=P_n+S_n Pn+1Pn=F1+F2+...+Fn=SnPn+1=Pn+Sn

到 这 里 , 我 们 就 将 S n 、 P n 、 F n 之 间 建 立 了 递 推 关 系 , 求 出 P n 后 , 可 以 解 得 : T n = n S n − P n 。 到这里,我们就将S_n、P_n、F_n之间建立了递推关系,求出P_n后,可以解得:T_n=nS_n-P_n。 SnPnFnPnTn=nSnPn

设 矩 阵 Q n = [ F n F n + 1 S n P n ] , 现 需 凑 出 4 × 4 变 换 矩 阵 A , 使 得 Q n A = Q n + 1 设矩阵Q_n=[F_n\quad F_{n+1}\quad S_n\quad P_n],现需凑出4×4变换矩阵A,使得Q_nA=Q_{n+1} Qn=[FnFn+1SnPn]4×4A使QnA=Qn+1

F n + 1 = 0 × F n + 1 × F n + 1 + 0 × S n + 0 × P n F_{n+1}=0×F_n+1×F_{n+1}+0×S_n+0×P_n Fn+1=0×Fn+1×Fn+1+0×Sn+0×Pn

F n + 2 = 1 × F n + 1 × F n + 1 + 0 × S n + 0 × P n F_{n+2}=1×F_n+1×F_{n+1}+0×S_n+0×P_n Fn+2=1×Fn+1×Fn+1+0×Sn+0×Pn

S n + 1 = 0 × F n + 1 × F n + 1 + 1 × S n + 0 × P n S_{n+1}=0×F_n+1×F_{n+1}+1×S_n+0×P_n Sn+1=0×Fn+1×Fn+1+1×Sn+0×Pn

P n + 1 = 0 × F n + 0 × F n + 1 + 1 × S n + 1 × P n P_{n+1}=0×F_n+0×F_{n+1}+1×S_n+1×P_n Pn+1=0×Fn+0×Fn+1+1×Sn+1×Pn

于 是 变 换 矩 阵 A = ∣ 0 1 0 0 1 1 1 0 0 0 1 1 0 0 0 1 ∣ , 初 始 矩 阵 Q 1 = [ F 1 F 2 S 1 P 1 ] = [ 1 1 1 0 ] 于是变换矩阵A=\begin{vmatrix}0\quad1\quad0\quad0\\1\quad1\quad1\quad0\\0\quad0\quad1\quad1\\0\quad0\quad0\quad1\end{vmatrix},初始矩阵Q_1=[F_1\quad F_{2}\quad S_1\quad P_1]=[1\quad 1\quad 1\quad 0] A=0100111000110001Q1=[F1F2S1P1]=[1110]

先 计 算 A n − 1 , 再 计 算 Q n = Q 1 A n − 1 = [ F n F n + 1 S n P n ] 先计算A^{n-1},再计算Q_n=Q_1A^{n-1}=[F_n\quad F_{n+1}\quad S_n\quad P_n] An1Qn=Q1An1=[FnFn+1SnPn]

最 后 得 到 T n = n S n − P n , 注 意 负 数 取 模 。 最后得到T_n=nS_n-P_n,注意负数取模。 Tn=nSnPn

代码:

#include<iostream>
#include<cstring>
#include<algorithm>

#define ll long long

using namespace std;

const int N=4;

int n,m;
ll f1[N][N]={{1,1,1,0}};  //Pn=n*Sn-Tn
ll A[N][N]={
    {0,1,0,0},
    {1,1,1,0},
    {0,0,1,1},
    {0,0,0,1}
};

void mul(ll a[][N],ll b[][N])
{
    ll c[N][N]={0};
    for(int i=0;i<N;i++)
        for(int j=0;j<N;j++)
            for(int k=0;k<N;k++)
                c[i][j]=(c[i][j]+a[i][k]*b[k][j]%m)%m;
    memcpy(a,c,sizeof c);
}

void quick_pow(ll a[][N],int k)
{
    ll E[N][N]={
        {1,0,0,0},
        {0,1,0,0},
        {0,0,1,0},
        {0,0,0,1}
    };
    while(k)
    {
        if(k&1) mul(E,a);
        mul(a,a);
        k>>=1;
    }
    memcpy(a,E,sizeof E);
}

int main()
{
    cin>>n>>m;
    
    quick_pow(A,n-1);
    mul(f1,A);
    
    ll ans=(n*f1[0][2]%m-f1[0][3]+m)%m;
    cout<<ans<<endl;
    
    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值