jun 碰到了挺多数列的题,线性递推,值又很大,直接推会超时,所以去网上找题解的时候,找到了矩阵快速幂以及杜教板子,杜教板子还没看懂,就以后再发
首先,快速幂,之前也学了整数的快速幂,复杂度是O(log^2n)这里就把模版贴一下
int poww(int a,int b){ int ans=1,base=a; while(b!=0){ if(b&1!=0) ans*=base; base*=base; b>>=1; } return ans; }
然后对于矩阵快速幂,只需要在快速幂中将两个整数a ,b改成矩阵形式就行了,然后相乘需要改成矩阵相乘
const int maxn=3; const int mod=1000000007; struct matrix{ long long a[maxn][maxn]; void init(){ memset(a,0,sizeof(a)); for(int i=0;i<maxn;i++) a[i][i]=1; } }; matrix mul(matrix a,matrix b){ matrix ans; for(int i=0;i<maxn;++i){ for(int j=0;j<maxn;++j){ ans.a[i][j] = 0; for(int k=0;k<maxn;++k){ ans.a[i][j]=(ans.a[i][j]+a.a[i][k]*b.a[k][j]+mod)%mod; } } } return ans; } matrix qpow(matrix a, int n){ matrix ans; ans.init(); while(n){ if(n&1) ans = mul(ans, a); a=mul(a,a); n/=2; } return ans; }
然后对于矩阵快速幂的运用来说,一般上用于线性递推的数列求第n项和
比如巨大的斐波拉契数列,如果直接用f(n)=f(n-1)+f(n-2)的话会超时,而如果用矩阵快速幂的形式去算的的话复杂度会降很多
即矩阵形式就是。
然后只需要对前面的那个矩阵求(n-1)次方就行了
还有的题目是需要自己去推的矩阵形式
列出最近写的两个题
一道是hdu的6185http://acm.hdu.edu.cn/showproblem.php?pid=6185
一道是牛客网小白赛6的洋灰三角https://www.nowcoder.com/acm/contest/136/J
第二题是需要求前n项和的但是解法还是相似的,递推式就是sum(n)=sum(n-1)+f(n)
就把第二题的代码附一下吧
#include <cstdio> #include <iostream> #include <string> #include <algorithm> #include <cstring> #include <cmath> #include <map> #include <stack> #define INF 1e9 using namespace std; const int maxn=3; const int mod=1000000007; struct matrix{ long long a[maxn][maxn]; void init(){ memset(a,0,sizeof(a)); for(int i=0;i<maxn;i++) a[i][i]=1; } }; matrix mul(matrix a,matrix b){ matrix ans; for(int i=0;i<maxn;++i){ for(int j=0;j<maxn;++j){ ans.a[i][j] = 0; for(int k=0;k<maxn;++k){ ans.a[i][j]=(ans.a[i][j]+a.a[i][k]*b.a[k][j]+mod)%mod; } } } return ans; } matrix qpow(matrix a, int n){ matrix ans; ans.init(); while(n){ if(n&1) ans = mul(ans, a); a=mul(a,a); n/=2; } return ans; } int main() { matrix ans,res; int n,k,q; memset(ans.a,0,sizeof(ans.a)); memset(res.a,0,sizeof(res.a)); cin>>n>>k>>q; if(n==1){ cout<<1<<endl; return 0; } ans.a[0][0]=1;ans.a[0][1]=1;ans.a[1][1]=k; ans.a[1][2]=1;ans.a[2][2]=1; res=qpow(ans,n); long long s=res.a[0][0]*1l%mod+res.a[0][1]*1l%mod+res.a[0][2]*q%mod; cout<<s%mod-1<<endl; }