快速幂

快速幂是一种用来快速计算  a^n(mod m)的方法,是一种log(n)的方法

 

一般快速幂

ll qpow(ll a,ll n)
{
    ll temp=1;
    while(n)
    {
        if(n&1)
            temp=(temp*a)%mod;
        a=(a*a)%mod;
        n=n>>1;
    }
    return temp;
}

超大数快速幂

ll multi(ll a,ll b,ll n)   //大数乘法 a*b mod n  目标乘法变加法,极端消耗时间
{
    a=a%n;b=b%n;
    ll res=0;
    while(b)
    {
        if(b&1)
        {
            res=res+a;
            if(res>=n)res=res-n;
        }
        a=a<<1;
        if(a>=n)a=a-n;
        b=b>>1;
    }
    return res;
}
ll qpow(ll a,ll b,ll mod)   //超大数快速幂
{
    ll temp=1;
    while(b)
    {
        if(b&1)
            temp=multi(temp,a,mod);
        a=multi(a,a,mod);
        b=b>>1;
    }
    return temp;
}

矩阵快速幂

由于a也可以是矩阵,故也有矩阵快速幂

typedef vector<vector<ll> > mat;   //定义矩阵

mat matmul(mat &a,mat &b)     //矩阵乘法
{
    int arow=a.size();
    int brow=b.size();
    int bcol=b[0].size();

    mat c(arow,vector<ll>(bcol)); //二维vector赋值空间,并自动初始化0(一维大小,二维内容)
    if(a[0].size()!=brow)         //判定矩阵之间是否可以相互乘积    一般情况下不会运行该步骤
    {
        printf("error matrix pow!\n");
        return c;
    }

    for(int i=0;i<arow;i++)
        for(int k=0;k<brow;k++)
            for(int j=0;j<bcol;j++)
                c[i][j]=(c[i][j]+a[i][k]*b[k][j])%mod; //如果矩阵中有负值,加上一个mod
    return c;
}

mat matpow(mat a,ll n)     //矩阵快速幂
{
    int len=a.size();
    mat b(len,vector<ll>(len));  //n*n的矩阵才能快速幂
    for(int i=0;i<len;i++)    //初始化为I矩阵
        b[i][i]=1;

    while(n)
    {
        if(n&1)
            b=matmul(b,a);
        a=matmul(a,a);
        n=n>>1;
    }
    return b;
}

//调用
int main()
{
    mat e(3,vector<ll>(3));
    e[0][0]=a;e[0][1]=0;e[0][2]=b;
    e[1][0]=1;e[1][1]=0;e[1][2]=0;
    e[2][0]=0;e[2][1]=0;e[2][2]=1;
    mat result=matpow(e,n-1);
    ll ans=(result[0][0]*((a*x+b)%mod)%mod+result[0][1]*x%mod+result[0][2])%mod;
}

用结构体写的matrix,使得matrix本身就是一种数据结构,该写法会浪费一定空间

struct Mat:vector<vector<ll> > //在这种写法的struct中都是自带this的,故要用this的写法
{
    Mat(){assign(0,vector<ll>(0,0));}
    Mat(int x,int y,ll num=0){assign(x,vector<ll>(y,num));}//初始化为x行,y列,元素值num不定义为0
    int row()const{return size();}            //返回行
    int col()const{return empty()?0:front().size();}   //返回列

    Mat operator*(const Mat &b)    //常量引用避免拷贝
    {
        int arow=row(),acol=col(),brow=b.row(),bcol=b.col();
        if(acol!=brow)return Mat();
        Mat c(arow,bcol);
        for(int i=0;i<arow;i++)
            for(int k=0;k<brow;k++)
                for(int j=0;j<bcol;j++)
                    c[i][j]=(c[i][j]+this->at(i).at(k)*b[k][j]%mod)%mod;    //或者at(i).at(k) ,如果矩阵中有负值,加上一个mod
        return c;
    }

    Mat pow(ll n)    //快速幂
    {
        if(row()!=col())return Mat();    //不是方阵就返回空
        Mat c(row(),row());
        for(int i=0;i<row();i++)c[i][i]=1;  //初始化矩阵I
        Mat a=(*this);                    //复制一个矩阵
        while(n)                         //快速幂
        {
            if(n&1) c=c*a;
            a=a*a;
            n=n>>1;
        }
        return c;
    }
};

//调用
int main()
{
    Mat e(3,3);
    e[0][0]=a;e[0][1]=0;e[0][2]=b;
    e[1][0]=1;e[1][1]=0;e[1][2]=0;
    e[2][0]=0;e[2][1]=0;e[2][2]=1;
    Mat result=e.pow(n-1);
    ll ans=(result[0][0]*((a*x+b)%mod)%mod+result[0][1]*x%mod+result[0][2])%mod;
}

算法中常用提速写法

struct Mat
{
    ll m[10][10];
    int row,col;
    Mat(){memset(m,0,sizeof(m));}
};
Mat mul(Mat a,Mat b)
{
    Mat ans;
    ans.row=a.row,ans.col=b.col;
    for(int i=1;i<=ans.row;i++)
        for(int j=1;j<=ans.col;j++)
            for(int k=1;k<=a.col;k++)
                ans.m[i][j]=(ans.m[i][j]+a.m[i][k]*b.m[k][j])%mod;
    return ans;
}
Mat mat_pow(Mat a,ll k)
{
    Mat e;
    e.row=a.row,e.col=a.col;
    for(int i=1;i<=a.row;i++)
        for(int j=1;j<=a.col;j++)
            e.m[i][j]=(i==j);

    while(k)
    {
        if(k&1)
            e=mul(e,a);
        a=mul(a,a);
        k=k>>1;
    }
    return e;
}

int main()
{
    Mat e;
    e.m[1][1]=x;e.m[1][2]=n*y;
    e.m[2][1]=y;e.m[2][2]=x;
    e.row=2,e.col=2;
    Mat res=mat_pow(e,k-1);
    int ans=(res.m[1][1]*x+res.m[1][2]*y)%mod;
}

简写矩阵乘法

struct Matrix
{
    ll m[13][13];
    int len;
    Matrix(){memset(m,0,sizeof(m));}
    void e(){memset(m,0,sizeof(m));for(int i=0;i<=len;i++)m[i][i]=1;}
    Matrix operator * (const Matrix &b)
    {
        Matrix c;c.len=len;
        for(int i=0;i<=len;i++)
            for(int j=0;j<=len;j++)
                for(int k=0;k<=len;k++)
                    c.m[i][j]=(c.m[i][j]+m[i][k]*b.m[k][j])%mod;
        return c;
    }
};
Matrix x;
void initx()
{
}
ll getans(int times)
{
    Matrix ans;ans.len=x.len;ans.e();
    while(times)
    {
        if(times&1) ans=ans*x;
        x=x*x;
        times=times>>1;
    }
    //return ans.m[(n-1)*10][0];
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
该资源内项目源码是个人的课程设计、毕业设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。 该资源内项目源码是个人的课程设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。
该资源内项目源码是个人的课程设计、毕业设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。 该资源内项目源码是个人的课程设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值