快速幂集合

快速幂

将幂进行二进制化

分解成1次2次4次的形式

比如2的5次

将5变成二进制形式101

过程表示为2的1次乘2的4次

每次循环只要将2进行平方

在幂对1与运算后若为1则运算,否则就跳过此次运算

这样就能使整个计算过程的时间复杂度缩减为logn

ll ksm(ll a,ll b,ll m){
    ll ans=1;
    while(b){
        if(b&1)
            ans*=a;
        ans%=m;
        a*=a;
        a%=m;
        b>>=1;
    }
    return ans%=m;
}

高精度快速幂

在原有的快速幂模版下

将乘法改为高精度乘法就能达成

这里用了一个辅助数组在乘法中

在ksm开始时因为先使底数为1,所以在计算结束后要减去1

别忘了判断最后一位是否为非负数

int res[N],q[N];

void mul(int a[],int b[]){
    int C[N];
    memset(C,0,sizeof(C));
    for(int i=1;i<=500;i++)
    {
        for(int j=1;j<=500;j++)
        {
            if(i+j-1>500)continue;
            C[i+j-1]+=a[i]*b[j];
            C[i+j]+=C[i+j-1]/10;
            C[i+j-1]%=10;
        }
    }
    for(int i=1;i<=500;i++)
        a[i]=C[i];
}

void gjd_ksm(int p){
    res[1]=1;
    q[1]=2;//底数
    while(p){
        if(p&1){
            mul(res,q);
        }
        mul(q,q);
        p>>=1;
    }
    res[1]--;
    int t=1;
    while(res[t]<0)
    {
        res[t+1]--;
        res[t]+=10;
        t++;
    }
}

矩阵快速幂

同样套用ksm模版

在进行矩阵乘法时,可以使用函数重载来使代码简便

ll n,k;
struct demo{
    ll q[N][N];
    demo(){
        memset(q,0,sizeof q);
    }
}res,e;

demo operator*(demo a,demo b){
    demo t;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            for(int k=1;k<=n;k++){
                t.q[i][j]+=(a.q[i][k]*b.q[k][j])%MOD;
                t.q[i][j]%=MOD;
            }
        }
    }
    return t;
}

void ksm(){
    for(int i=1;i<=n;i++){
        res.q[i][i]=1;
    }
    while(k){
        if(k&1){
            res=res*e;
        }
        e=e*e;
        k>>=1;
    }
}

void solve(){
    cin >> n >> k;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            cin >> e.q[i][j];
        }
    }
    ksm();
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            cout << res.q[i][j] <<' ';
        }
        cout << endl;
    }
}

矩阵加速

在某些给出类似斐波那契的递归函数题型时,可以使用矩阵加速

需要初始的前几位值组成基矩阵

再创建一个加速矩阵最为需要乘的转换方程

意为基矩阵乘上几次加速矩阵便能得出第几个值

ll n,m;
struct demo{
    ll q[4][4];
    demo(){
        memset(q,0,sizeof q);
    }
}res,e;

demo operator*(demo a,demo b){
    demo t;
    for(int i=1;i<=3;i++){
        for(int j=1;j<=3;j++){
            for(int k=1;k<=3;k++){
                t.q[i][j]+=(a.q[i][k]*b.q[k][j])%MOD;
                t.q[i][j]%=MOD;
            }
        }
    }
    return t;
}

void ksm(){
    memset(e.q,0,sizeof e.q);
    memset(res.q,0,sizeof res.q);
    res.q[1][1]=res.q[1][2]=res.q[1][3]=1;
    e.q[1][1]=e.q[2][3]=e.q[1][2]=e.q[3][1]=1;
    n-=3;
    while(n){
        if(n&1){
            res=res*e;
        }
        e=e*e;
        n>>=1;
    }
}

void solve(){
    cin >> n;
    if(n<=3){
        cout << 1 << endl;
    }else{
        ksm();
        cout << res.q[1][1] << endl;
    }
}

  • 6
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值