数论-矩阵快速幂及其简单构造方法

[用途]

n较大时,求简单递推式 F n = ∑ i = 1 n − 1 k i F n − i + s o m e t h i n g , ( k i ∈ Z ) F_n=\sum\limits_{i=1}^{n-1}{k_iF_{n-i}}+something,(k_i\in Z) Fn=i=1n1kiFni+something,(kiZ)

[构造形式]

构建矩阵X,A,B,使矩阵X乘以矩阵A等于矩阵B , (注意一般情况下矩阵不满足交换律!!!)

[构造方法]

  • F n − i F_{n-i} Fni的项依次按照顺序填入矩阵A中
  • s o m e t h i n g something something中常数项与 ( n − 1 ) k (n-1)^k (n1)k项也依次填入矩阵A中
  • s o m e t h i n g something something n k n^k nk的项根据二项式定理
    ( 1 + x ) n = ∑ i = 0 n C n i x n (1+x)^{n}=\sum\limits_{i=0}^n{C_{n}^{i}x^{n}} (1+x)n=i=0nCnixn
    n k = ( 1 + ( n − 1 ) ) k = ∑ i = 0 k C k i ( n − 1 ) i n^k=(1+(n-1))^k=\sum\limits_{i=0}^k{C_{k}^{i}(n-1)^{i}} nk=(1+(n1))k=i=0kCki(n1)i
    这样就转化为了含 ( n − 1 ) k (n-1)^k (n1)k的项

构 建 后 的 矩 阵 A 类 似 于 : [ F n − 1 0 0 . . . 0 F n − 2 0 0 . . . 0 . . . 0 0 . . . 0 ( n − 1 ) k 0 0 . . . 0 ( n − 1 ) k − 1 0 0 . . . 0 . . . 0 0 . . . 0 ( n − 1 ) 0 0 0 . . . 0 ] 构建后的矩阵A类似于:\left[ \begin{matrix} F_{n-1} &0&0&...&0\\ F_{n-2} &0&0&...&0\\ \quad ...&0&0&...&0\\ (n-1)^k &0&0&...&0\\ (n-1)^{k-1} &0&0&...&0\\ \quad ...&0&0&...&0\\ (n-1)^0 &0&0&...&0\\ \end{matrix} \right] AFn1Fn2...(n1)k(n1)k1...(n1)000000000000000.....................0000000

构 建 后 的 矩 阵 B 类 似 于 : [ F n 0 0 . . . 0 F n − 1 0 0 . . . 0 . . . 0 0 . . . 0 n k 0 0 . . . 0 n k − 1 0 0 . . . 0 . . . 0 0 . . . 0 n 0 0 0 . . . 0 ] 构建后的矩阵B类似于:\left[ \begin{matrix} F_{n} &0&0&...&0\\ F_{n-1} &0&0&...&0\\ \quad ...&0&0&...&0\\ n^k &0&0&...&0\\ n^{k-1} &0&0&...&0\\ \quad ...&0&0&...&0\\ n^0 &0&0&...&0\\ \end{matrix} \right] BFnFn1...nknk1...n000000000000000.....................0000000
然后根据矩阵乘法求X
B [ i ] [ j ] 为 矩 阵 X 的 第 i 行 与 矩 阵 A 的 第 j 列 对 应 相 乘 所 得 的 和 , 由 已 知 递 推 式 求 系 数 即 可 B[i][j]为矩阵X的第i行与矩阵A的第j列对应相乘所得的和,由已知递推式求系数即可 B[i][j]XiAj,

[代码]

以hdu6470为例

F n = 2 F n − 2 + F n − 1 + n 3 F_n=2F_{n-2}+F_{n-1}+n^3 Fn=2Fn2+Fn1+n3
根据上述有
A = [ F n − 1 0 0 0 0 0 F n − 2 0 0 0 0 0 ( n − 1 ) 3 0 0 0 0 0 ( n − 1 ) 2 0 0 0 0 0 ( n − 1 ) 1 0 0 0 0 0 1 0 0 0 0 0 ] A=\left[ \begin{matrix} F_{n-1} &0&0&0&0&0\\ F_{n-2} &0&0&0&0&0\\ (n-1)^3 &0&0&0&0&0\\ (n-1)^2 &0&0&0&0&0\\ (n-1)^{1} &0&0&0&0&0\\ 1 &0&0&0&0&0 \end{matrix} \right] A=Fn1Fn2(n1)3(n1)2(n1)11000000000000000000000000000000 , B = [ F n 0 0 0 0 0 F n − 1 0 0 0 0 0 n 3 0 0 0 0 0 n 2 0 0 0 0 0 n 1 0 0 0 0 0 1 0 0 0 0 0 ] B=\left[ \begin{matrix} F_{n} &0&0&0&0&0\\ F_{n-1} &0&0&0&0&0\\ n^3 &0&0&0&0&0\\ n^2 &0&0&0&0&0\\ n^{1} &0&0&0&0&0\\ 1 &0&0&0&0&0 \end{matrix} \right] B=FnFn1n3n2n11000000000000000000000000000000

X = [ 1 2 1 3 3 1 1 0 0 0 0 0 0 0 1 3 3 1 0 0 0 1 2 1 0 0 0 0 1 1 0 0 0 0 0 1 ] X=\left[ \begin{matrix} 1&2&1&3&3&1\\ 1&0&0&0&0&0\\ 0 &0&1&3&3&1\\ 0 &0&0&1&2&1\\ 0 &0&0&0&1&1\\ 0 &0&0&0&0&1 \end{matrix} \right] X=110000200000101000303100303210101111

设基准点是F[2],矩阵 A = [ 2 ( 即 F [ 2 ] ) 0 0 0 0 0 1 即 ( F [ 1 ] ) 0 0 0 0 0 8 0 0 0 0 0 4 0 0 0 0 0 2 0 0 0 0 0 1 0 0 0 0 0 ] A=\left[ \begin{matrix} 2(即F[2]) &0&0&0&0&0\\ 1 即(F[1])&0&0&0&0&0\\ 8 &0&0&0&0&0\\ 4 &0&0&0&0&0\\ 2 &0&0&0&0&0\\ 1 &0&0&0&0&0 \end{matrix} \right] A=2(F[2])1(F[1])8421000000000000000000000000000000

求F[n],矩阵 B = X n − 2 ∗ A B=X^{n-2}*A B=Xn2A,即F[n]=B[0][0]

#include<cstdio>
#include<cstring>
using namespace std;
typedef long long LL;
const LL N=6;
const LL mod=123456789;
struct jz{
    LL A[N][N];
    inline jz friend operator*(jz x,jz y){
        jz ans;
        memset(ans.A,0,sizeof(ans.A));
        for(LL i=0;i<N;++i)
            for(LL j=0;j<N;++j)
                for(LL k=0;k<N;++k)
                    ans.A[i][j]=(ans.A[i][j]+x.A[i][k]*y.A[k][j])%mod;
        return ans;
    }
};
jz jzksm(jz x,LL n)
{
    jz ans;
    memset(ans.A,0,sizeof(ans.A));
    for(LL i=0;i<N;++i)ans.A[i][i]=1;
    while(n){
        if(n&1)ans=ans*x;
        n>>=1;
        x=x*x;
    }
    return ans;
}
int main()
{
    jz first={
        2,0,0,0,0,0,
        1,0,0,0,0,0,
        8,0,0,0,0,0,
        4,0,0,0,0,0,
        2,0,0,0,0,0,
        1,0,0,0,0,0,
    };
    jz x={
        1,2,1,3,3,1,
        1,0,0,0,0,0,
        0,0,1,3,3,1,
        0,0,0,1,2,1,
        0,0,0,0,1,1,
        0,0,0,0,0,1,
    };
    LL n,T;
    scanf("%lld",&T);
    while(T--){
        scanf("%lld",&n);
        jz ans=jzksm(x,n-2)*first;
        printf("%lld\n",ans.A[0][0]);
    }
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值