矩阵快速幂
前置知识
原理
首先是矩阵乘法
A×B中 a的列必须等于b的行,A×B的每一行就是A中对应的行*B中对应的列。
然后我们就可以写一个结构体来重载乘法以及其他运算符。
//别问我为什么我zz地用了class,问就是我chun
class mat{
public:
int n,m;
ll v[maxn][maxn];
mat(int n,int m):n(n),m(m){}
void init()//初始化
{
memset(v,0,sizeof(v));
}
void init1()
{
for(int i=0;i<maxn;i++)
for(int j=0;j<maxn;j++)
v[i][j]=(i==j); //单位矩阵
}
mat operator* (const mat B) const//矩阵乘法 A(n,k)*B(k,m)=C(n,m);
{
mat C(n,B.m);
C.init();
for(int i=0;i<=n;i++)
for(int j=0;j<=B.m;j++)
for(int k=0;k<=m;k++)
C.v[i][j]=(C.v[i][j]+v[i][k]*B.v[k][j]%Mod)%Mod;//Mod
return C;
}
mat operator ^ (ll t)//矩阵快速幂 n=m时可用
{
mat ans(n,n),now(n,n);
ans.init1();
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
now.v[i][j]=v[i][j];
while(t)
{
if(t&1) ans=ans*now;
now=now*now;
t>>=1;
}
return ans;
}
}
其他性质:
既然可以进行矩阵的乘法了,那么矩阵快速幂就是把原来的整型改为矩阵类型。
但要注意的是能进行矩阵快速幂的矩阵 行数等于列数
mat operator ^ (ll t)//矩阵快速幂 n=m时可用
{
mat ans(n,n),now(n,n);
ans.init1();
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
now.v[i][j]=v[i][j];
while(t)
{
if(t&1) ans=ans*now;
now=now*now;
t>>=1;
}
return ans;
}
解决了这个问题就可以直接套了!
用处
那么问题来了
这个玩意儿有什么用
貌似可以推一些有递推规律的递推式
样例1
比如最基础的斐波那契数列
首先构造初始矩阵,把递推式要用到的所有元素都加进去
然后构造转移矩阵,因为递推式的下一级的过程为
所以易得转移矩阵 a,来使a * xi=x(i+1)
转移矩阵fr为
ps:转移矩阵真的可以用填空法做,就是有的麻烦
那么求第n个项的时候就可以变为
样例2
这里有两个需要递推的元素,n和f,f后一位需要 f、n , n后一位n+1需要n、1
所以可以得到初始矩阵
以及第n个矩阵
所以就可以开始填空了:
第一行 3 1 0
第二行 0 1 1
第三行 0 0 1
然后代码实现填进去就可以了
设转移矩阵为 ex ,初始矩阵为 fr
得到第n个矩阵以及fn
ex=ex^n;
n=ex*n;
ll fn=n.v[0];