P1939 【模板】矩阵加速(数列)

本文介绍了一种使用矩阵乘法快速幂解决特定问题的方法。通过定义初始矩阵并利用快速幂加速计算过程,解决了序列计算中重复计算的问题。文章提供了一个完整的C++实现示例,并详细解释了关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

luogu 传送门
矩阵乘法快速幂,注意记录过程量;
还有就是如果前面已经算过了,直接赋值就好了。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring> 
#define LL long long
#define MOD 1000000007
using namespace std;
LL A[4][4]={
    0,0,0,0,
    0,1,1,0,
    0,0,0,1,
    0,1,0,0,
           };
LL ans[2][4],B[4][4],C[4][4],bak[4][4],a[109];
int T;
struct H{
    LL n;int id;
}q[109];
bool cmp(H x,H y){return x.n<y.n;}; 
void Fast_Pow(LL p)
{
    p--;
    for(int i=1;i<=3;i++) for(int j=1;j<=3;j++) B[i][j]=C[i][j]=A[i][j];
    while(p)
    {
        if(p%2)//B*C 
        {
            for(int i=1;i<=3;i++) for(int j=1;j<=3;j++) bak[i][j]=B[i][j],B[i][j]=0;
            for(int i=1;i<=3;i++)
             for(int j=1;j<=3;j++)
              for(int k=1;k<=3;k++)
               B[i][j]=(B[i][j]+bak[i][k]*C[k][j]%MOD)%MOD;
        }
        //C*C 
        for(int i=1;i<=3;i++) for(int j=1;j<=3;j++) bak[i][j]=C[i][j],C[i][j]=0;
        for(int i=1;i<=3;i++)
         for(int j=1;j<=3;j++)
          for(int k=1;k<=3;k++)
           C[i][j]=(C[i][j]+bak[i][k]*bak[k][j]%MOD)%MOD;

        p/=2;
    }
    for(int i=1;i<=3;i++) bak[1][i]=ans[1][i],ans[1][i]=0;
    ans[1][1]=(bak[1][1]*B[1][1]%MOD+bak[1][2]*B[2][1]%MOD+bak[1][3]*B[3][1]%MOD)%MOD;
    ans[1][2]=(bak[1][1]*B[1][2]%MOD+bak[1][2]*B[2][2]%MOD+bak[1][3]*B[3][2]%MOD)%MOD;
    ans[1][3]=(bak[1][1]*B[1][3]%MOD+bak[1][2]*B[2][3]%MOD+bak[1][3]*B[3][3]%MOD)%MOD; 
} 
int main()
{
    scanf("%d",&T);
    for(int i=1;i<=T;i++)
    {
        scanf("%lld",&q[i].n);
        q[i].id=i;
    }
    ans[1][1]=1,ans[1][2]=1,ans[1][3]=1;
    sort(q+1,q+T+1,cmp);
    for(int i=1;i<=T;i++)
    {
        LL n=q[i].n;
        if(n<=3&&n>=1) {a[q[i].id]=1;continue;}
        if(i==1) Fast_Pow(q[1].n-3); 
        else if(n-q[i-1].n)Fast_Pow(n-q[i-1].n);
        a[q[i].id]=ans[1][1];
    }
    for(int i=1;i<=T;i++) printf("%lld\n",a[i]);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值