矩阵快速幂 模板

根据牛客多校所写:https://ac.nowcoder.com/acm/contest/885/B 

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1000100;
const int NUM=2;//当前矩阵是几行几列的
ll MOD;//取模
char s[maxn];
struct Matrix {
    ll a[NUM][NUM];
    Matrix() {
        memset(a,0,sizeof(a));
    }
    Matrix operator*(const Matrix  y) {
        Matrix  ans;
        for(int i=0; i<NUM; i++)
            for(int j=0; j<NUM; j++)
                for(int k=0; k<NUM; k++)
                    ans.a[i][j]=(ans.a[i][j]+(a[i][k]*y.a[k][j])%MOD+MOD)%MOD;
					//有时候+MOD会出现段错误、超时等问题,很玄学,视具体情况而定 
        return ans;
    }
    /*void operator=(const Matrix b) {
        for(int i=0; i<NUM; i++)
            for(int j=0; j<NUM; j++)
                a[i][j]=b.a[i][j];
    }*///重载 = ,应该是不用重载也可以,但好像某些题目会卡,还是玄学问题,必要时加上
	//重载之后,时间会增加,但某些玄学题目会过 
};
Matrix mat_pow(Matrix c, ll n) {
    Matrix res;
    for(int i=0;i<NUM;i++){
        for(int j=0;j<NUM;j++){
            if(i==j) res.a[i][j]=1;
            else res.a[i][j]=0;
        }
    }
    while(n) {
        if(n&1) res=res*c;
        c=c*c;
        n=n>>1;
    }
    //return res.a[0][0];  //根据实际需要二选一
    return res;
}
Matrix qpow10(Matrix c,char *s){
    int len=strlen(s)-1;
    Matrix res;
    for(int i=0;i<NUM;i++){
        for(int j=0;j<NUM;j++){
            if(i==j) res.a[i][j]=1;
            else res.a[i][j]=0;
        }
    }
    for(int i=len;i>=0;i--){
        if(s[i]-'0'>0){
            Matrix E;
            E=(mat_pow(c,s[i]-'0'));
            res=res*E;
        }
        c=mat_pow(c,10);
    }
    return res;
}
int main() {
    // a b 两个矩阵,该模板可以快速求出 a^n * b 的结果,倘若n过大,我们还可以用字符串
	//将其读入,用上面的pow10函数对其进行处理
	// 根据题目的要求,更改上述NUM和MOD的值 
    ll x0,x1,a,b;
    scanf("%lld%lld%lld%lld%s%lld",&x0,&x1,&a,&b,s,&MOD);//这里输入题目中要求的数值
	 
	Matrix mat;
    mat.a[0][0]=a;mat.a[0][1]=b;mat.a[1][0]=1;mat.a[1][1]=0;
	//初始矩阵赋值
    
	mat=qpow10(mat,s);
    ll ans=((x1*mat.a[1][0])%MOD+(x0*mat.a[1][1])%MOD)%MOD;
    //有时候,我们需要输出矩阵的某一个元素的值,有时候需要用题中的数据与矩阵中的
	//某些元素的值再次相乘,得出正确答案
	 
    printf("%lld\n",ans);
    return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值