一、矩阵的计算
矩阵的加法与乘法本人就不在此赘述了,这里描述一下对于矩阵乘法与矩阵加法的优化。
对于矩阵乘法。
我们需要先知道 矩阵是满足结合率的
也就是说 A*B*C==A*(B*C)
这其实非常好证明,你将整个矩阵式子打开会发现就是乘法的结合律。
那么假如我们要求A^k,即A的k次幂。
那我们就会想,能否用快速幂进行加速,事实上是可以的。
假如k=10的话
A^10=A*A*A*A*A*A*A*A*A*A
通过分配率
A^10=A^8*A^2
那么就会发现,这与快速幂是一样的,那么便可以用快速幂加速。
对于矩阵加法。
假如说要求A^1+A^2+A^3+…+A^k的和
假如A是一个n*n的矩阵
对于暴力的复杂度为O(n^2k)
但是我们会发现假如A是一个数的话,那么求的是一个等比数列的和,那么根据高中数学数列的知识。
显然
A^1+A^2+A^3+A^4等价于A^1+A^2+A^2*(A^1+A^2)=(1+A^2)
∗
<script type="math/tex" id="MathJax-Element-40">*</script>(A^1+A^2)
这实际上就是一个二分
题目链接
附上个人很丑的代码,代码中的^重载即是快速幂
#include<bits/stdc++.h>
#define fer(i,j,n) for(int i=j;i<=n;i++)
#define far(i,j,n) for(int i=j;i>=n;i--)
#define ll long long
const int maxn=1010;
const int INF=1e9+7;
using namespace std;
/*----------------------------------------------------------------------------*/
inline ll read()
{
char ls;ll x=0,sng=1;
for(;ls<'0'||ls>'9';ls=getchar())if(ls=='-')sng=-1;
for(;ls>='0'&&ls<='9';ls=getchar())x=x*10+ls-'0';
return x*sng;
}
/*----------------------------------------------------------------------------*/
int n,k,mod,num;
struct kaga
{
ll v[31][31];
kaga friend operator *(kaga a,kaga b)
{
kaga c;
fer(i,1,n)
fer(j,1,n)
{
c.v[i][j]=0;
fer(k,1,n)
c.v[i][j]=(c.v[i][j]+a.v[i][k]*b.v[k][j])%mod;
}
return c;
}
kaga friend operator +(kaga a,kaga b)
{
fer(i,1,n)
fer(j,1,n)
a.v[i][j]=(a.v[i][j]+b.v[i][j])%mod;
return a;
}
kaga friend operator ^(kaga a,int k)
{
kaga ans;
fer(i,1,n)
fer(j,1,n)if(i==j)ans.v[i][j]=1;
for(;k;k>>=1,a=a*a)
if(k&1)ans=ans*a;
return ans;
}
void friend print(kaga a)
{
fer(i,1,n)
{
fer(j,1,n)
cout<<a.v[i][j]%mod<<" ";
cout<<endl;
}
}
}a,b,ans;
kaga solve(kaga a,int k)
{
if(k==1)return a;
if(k&1)
{
kaga c=solve(a,k>>1);
k++;k>>=1;
kaga d=a^k;
return (d+b)*c+d;
}
else
{
kaga c=solve(a,k>>1);
k>>=1;
return ((a^k)+b)*c;
}
}
int main()
{
n=read();k=read();mod=read();
fer(i,1,n)
fer(j,1,n)
{
if(i==j)b.v[i][j]=1;
else b.v[i][j]=0;
a.v[i][j]=read()%mod;
}
ans=solve(a,k);
print(ans);
}