1:基础知识
(1)矩阵快速幂其实就是一个矩阵乘法,加快速幂的思想,下面简单介绍一下矩阵乘法怎么运算。
对于矩阵C=A*B
其中c[i][j]为A的第i行与B的第j列对应乘积的和,即:
代码:
有二种写法,一般这种就够用了,这里只介绍这种
mat operator *(mat x,mat y) //重载乘法
{
mat ret;
for(int i=0;i<mx;i++)//mx可以根据题目要求具体变化
for(int j=0;j<mx;j++)
{
ret.m[i][j]=0;
for(int k=0;k<mx;k++)
ret.m[i][j]=(x.m[i][k]*y.m[k][j]+ret.m[i][j])%mod;
}
return ret;
}
下面给出通用模板,个人觉得一个很好的模板,有些模板看着看着就晕了。然后我总结了一个可以通用的模板。
#include<iostream>
#include<algorithm>
#include<map>
#include<cstring>
#include<vector>
#include<cstdio>
#include<cmath>
using namespace std;
typedef long long ll;
const ll mod=10000;
const ll mx=2;//根据题目改
struct mat{
ll m[mx][mx];
};
mat operator *(mat x,mat y)//矩阵乘法
{
mat ret;
for(int i=0;i<mx;i++)
for(int j=0;j<mx;j++)
{
ret.m[i][j]=0;
for(int k=0;k<mx;k++)
ret.m[i][j]=(x.m[i][k]*y.m[k][j]+ret.m[i][j])%mod;
}
return ret;
}
mat ff(mat a,ll n)//快速幂部分
{
mat ret;
memset(ret.m,0,sizeof ret.m);
for(int i=0;i<mx;i++) ret.m[i][i]=1;
while(n)
{
if(n&1) ret=ret*a;
a=a*a;
n>>=1;
}
return ret;
}
int main()
{
int t,n;
while(cin>>n)
{
if(n==-1)
break;
else if(n==0)
printf("0\n");
else if(n==1)
printf("1\n");
else
{
mat a;//A1首项
memset(a.m,0,sizeof a.m);
a.m[0][0]=1;
a.m[1][0]=0;
mat b={//公比
1, 1,
1, 0
};
a=ff(b,n-1)*a;//套公式就完事了
cout<<a.m[0][0]<<endl;
}
}
return 0;
}
2: 技巧
首先我们先说下矩阵快速幂有什么作用,它可以处理一些递推式,一般而言,我们直接一步步递推是O(n)的算法,对于n很大时,就妥妥的超时,然后我们就可以通过矩阵快速幂把时间复杂度降到O(m^3*log(n)),m是矩阵的大小,n是求的第几项。
现在我先解释一下为什么它通用:
对于矩阵而言。所以矩阵都可以看作:
这个式子(大家可以自己推下,算下,T的一次方,T的二次方,在乘上A1的值,得出来的结果。具体证明我也不会 ),看成一个等比数列,A1是首项,T是公比
然后我们就求An就好了。
举个栗子
poj 3070
就拿我们最常见的Fibonacci来说(下面是重点,请大家牢记这些步骤)
第一步:求递推式
(有些题是给出递推式的,有些题是要自己推的,求递推式没啥技巧,一般而言,求出前面几项,找规律。主要还是多练习,就有感觉了。)
第二步:求出公比T的矩阵
第三步:套模板
就那这题来说,我们可以根据递推式fn=fn-1+fn-2;
就很容易想到
T就等于
然后我们就直接套板子,输出就好了,代码就是模板。
下面给出一些常见的递推式:
1.f(n)=af(n-1)+bf(n-2)+c;(a,b,c是常数)
2.f(n)=c^n-f(n-1) ;(c是常数)
3.f(n)=a*f(n-1)+c^n
3:应用
1.poj 3233
题解
我的ac代码:https://paste.ubuntu.com/p/hM6mXdFjpS/
2.hdu5015
题解
我的ac代码:https://paste.ubuntu.com/p/fP5MRqtKxg/
3hdu1757
题解
我的ac代码:https://paste.ubuntu.com/p/xHNxWmMDTy/
4.hdu3483
题解,关键还是找递推式的规律Sn=Sn-1+X
我的ac代码:https://paste.ubuntu.com/p/6JG8D2Pqj3/
5.hdu1575
题目比较简单,直接给出ac代码,矩阵的迹,主对角线上的元素之和
6.hdu2276
题解,这题思路构造矩阵
我的ac代码:
https://paste.ubuntu.com/p/Gh9rCzSKfG/
7.hdu2855
题解,结论题,也可以是规律题
我的ac代码:https://paste.ubuntu.com/p/8MzvK6y7Z9/
8.hdu4565
题解,这题算是我写了很久的题,至于推结论我也不是会,(这是一类技巧题),但知道它怎么来的了,不会的同学可以私聊我
我的ac代码:https://paste.ubuntu.com/p/PhV46jnMjY/