快速幂是一种用来快速计算 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];
}