bzoj2875 [noi2012]随机数生成器(矩阵倍增)

挺裸的矩阵倍增。。。就是再处理一下ll*ll.思想类似快速幂,例如对x*y,把x变成二进制,y去倍增,每次都mod m,变乘法为许多次加法,保证不会溢出。

#include <cstdio>
#include <cstring>
#define ll long long
ll g,aa,c,x0,n,mod;
inline ll mul(ll x,ll y){//ll*ll的处理
    ll res=0;
    for(;x;x>>=1,y=(y+y)%mod)
        if(x&1) res=(res+y)%mod;
    return res;
}
struct matrix{
    ll mat[2][2];
    matrix(bool op){
        memset(mat,0,sizeof(mat));
        if(op) mat[0][0]=1,mat[1][1]=1;
    }
    matrix operator*(matrix b){
        matrix res(0);
        for(int i=0;i<2;++i)
            for(int j=0;j<2;++j)
                for(int k=0;k<2;++k)
                    res.mat[i][j]=(res.mat[i][j]+mul(mat[i][k],b.mat[k][j]))%mod;
        return res;
    }
    matrix operator^(ll k){
        matrix res(1);matrix b(0);
        memcpy(b.mat,mat,sizeof(mat));
        for(;k;k>>=1,b=b*b)
            if(k&1) res=res*b;
        return res;
    }
}trans(0),a(0);
int main(){
//  freopen("a.in","r",stdin);
    scanf("%lld%lld%lld%lld%lld%lld",&mod,&aa,&c,&x0,&n,&g);
    a.mat[0][0]=x0;a.mat[0][1]=c;
    trans.mat[0][0]=aa;trans.mat[1][1]=trans.mat[1][0]=1;
    a=a*(trans^n);
    printf("%lld\n",a.mat[0][0]%g);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值