有些东西很慢,然后就变得很快了。二分矩阵快速幂是解决矩阵幂乘的一种方法,主要思想是采用分治方法。
先来一个简单的数的幂运算。
long long quickpow(long long m , long long n , long long k) {
long long ans = 1;
while(n) {
if(n&1) //如果n是奇数
ans = (ans * m) % k;
n = n >> 1;//位运算“右移1类似除1”
m = (m * m) % k;
}
return ans;
}
对于矩阵的幂运算,先给出一个模板。
更新内容:在矩阵加法和矩阵乘法中,原先的取余方式if(a.m[i][j]>=MOD)a.m[i][j]%=MOD;
存在负数BUG。还是使用朴素的取余方式吧。
struct matrix
{
#define M 105
#define MOD 100000
ll m[M][M],r,c;
void init(ll r1,ll c1)
{
r=r1,c=c1;
for(int i=0;i<r1;i++)for(int j=0;j<c1;j++)m[i][j]=0;
}
void prt()
{
for(int i=0;i<r;i++)
{
for(int j=0;j<c;j++)printf("%I64d ",m[i][j]);
puts("");
}
puts("");
}
};
//矩阵加法
matrix Plus(matrix a,matrix b)
{
for(int i=0;i<a.r;i++)
for(int j=0;j<a.c;j++)
{
a.m[i][j]+=+b.m[i][j];
/*//IF MOD
//if(a.m[i][j]>=MOD)a.m[i][j]%=MOD;
a.m[i][j]=(a.m[i][j]%MOD+MOD)%MOD;*/
}
return a;
}
//矩阵乘法 条件:a.c=b.r 结果:c.r=a.r c.c=b.c
matrix mult(matrix a,matrix b)
{
matrix ans;ans.init(a.r,b.c);
for(int i=0;i<a.r;i++)
for(int k=0;k<a.c;k++)if(a.m[i][k])
for(int j=0;j<b.c;j++)
{
ans.m[i][j]+=a.m[i][k]*b.m[k][j];
/*//IF MOD
//if(ans.m[i][j]>=MOD)ans.m[i][j]%=MOD;
ans.m[i][j]=(ans.m[i][j]%MOD+MOD)%MOD;*/
}
return ans;
}
//快速幂
matrix pow(matrix a,ll n)
{
matrix b,t=a;b.init(a.r,a.c);
//构造单位矩阵
for(int i=0;i<b.c;i++)b.m[i][i]=1;
while(n>=1)
{
if(n&1)b=mult(b,t);
n>>=1;
t=mult(t,t);
}
return b;
}
(经测试,运算符重载的效率比上边的效率低)
#define MOD 10001
struct Mat {
int n,m;
int mat[5][5];
Mat() {
memset(mat,0,sizeof(mat));
n = m = 5; //矩阵的大小
};
};
Mat operator *(Mat a,Mat b) {
Mat c;
c = Mat();
c.n = a.n,c.m = b.m;
for(int i=1;i<=a.n;i++) {
for(int k=1;k<=a.m;k++) {
if(a.mat[i][k]!=0){ //这里优化一下,对于稀疏矩阵可以节省一半左右的时间
for(int j=1;j<=b.m;j++) {
c.mat[i][j] += (a.mat[i][k]*b.mat[k][j])%MOD;
c.mat[i][j] %= MOD;
}
}
}
}
return c;
}
Mat operator +(Mat a,Mat b) {
Mat c;
c = Mat();
c.n = a.n,c.m = a.m;
for(int i=1;i<=a.n;i++) {
for(int j=1;j<=a.m;j++) {
c.mat[i][j] = a.mat[i][j]+b.mat[i][j];
c.mat[i][j] %= MOD;
}
}
return c;
}
Mat operator ^(Mat a,long long k) {
Mat c;
int i,j;
c = Mat();
c.n = a.n,c.m = a.n;
for(i=1;i<=a.n;i++)c.mat[i][i] = 1;
while(k) {
if(k&1) {
c = c*a;
}
a = a*a;
k>>=1;
}
return c;
}
void out(Mat a) {
int i,j;
for(i=1;i<=a.n;i++) {
for(j=1;j<=a.m;j++) {
cout<<a.mat[i][j]<<" ";
}
cout<<endl;
}
}