[模板]矩阵的快速幂
原理:
$\left( {\begin{array}{*{20}{c}}
{{F_{n + 2}}}\\
{{F_{n + 1}}}
\end{array}} \right) = \left( {\begin{array}{*{20}{c}}
1&1\\
1&0
\end{array}} \right)\left( \begin{array}{l}
{F_{{\rm{n + }}1}}\\
{F_n}
\end{array} \right)$
记这个矩阵为A,则有
$\left( {\begin{array}{*{20}{c}}
{{F_{n + 1}}}\\
{{F_n}}
\end{array}} \right) = {A^n}\left( \begin{array}{l}
{F_1}\\
{F_0}
\end{array} \right)$
注意这种初始化方式,matrix为只有一个二维数组的结构体
1 struct matrix 2 { 3 long long m[4][4]; 4 }; 5 matrix ans = { 1,0,0,0, 6 0,1,0,0, 7 0,0,1,0, 8 0,0,0,1,}; 9 matrix base = { 1,1,1,0, 10 1,0,0,0, 11 0,1,0,0, 12 1,0,0,1,};
第一种要注意,界限的确定,要保证符合所有矩阵。
1 #include<cstdio> 2 #include<cstring> 3 #include<cstdlib> 4 #include<algorithm> 5 using namespace std; 6 typedef long long ll; 7 struct mat{ 8 ll m[2][2]; 9 }; 10 ll n=10; 11 ll mod=10000; 12 mat mul(mat &A,mat &B){ 13 mat C={0}; 14 for(int i=0;i<2;i++){ 15 for(int j=0;j<2;j++){ 16 for(int k=0;k<2;k++){ 17 C.m[i][j]=(C.m[i][j]+A.m[i][k]*B.m[k][j])%mod; 18 } 19 } 20 } 21 return C; 22 } 23 mat pow(mat A,ll n){ 24 mat B={0}; 25 B.m[0][0]=B.m[1][1]=1; 26 while(n>0){ 27 if(n&1) B=mul(B,A); 28 A=mul(A,A); 29 n>>=1; 30 } 31 return B; 32 } 33 int main(){ 34 mat A={0}; 35 A.m[0][0]=A.m[1][0]=A.m[0][1]=1; 36 A=pow(A, n); 37 printf("%lld\n",A.m[1][0]); 38 }
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 typedef vector<ll> vec; 5 typedef vector<vec> mat; 6 ll n=10; 7 const int M=10000; 8 mat mul(mat &A,mat &B){ 9 mat C(A.size(),vec(B[0].size())); 10 for(int i=0;i<(int)A.size();i++){ 11 for(int j=0;j<(int)B[0].size();j++){ 12 for(int k=0;k<(int)B.size();k++){ 13 C[i][j]=(C[i][j]+A[i][k]*B[k][j])%M; 14 } 15 } 16 } 17 return C; 18 } 19 20 mat pow(mat A,ll n){ 21 mat B(A.size(),vec(A.size())); 22 for(int i=0;i<(int)A.size();i++){ 23 B[i][i]=1;//单位矩阵 24 } 25 while(n>0){ 26 if(n&1) B=mul(B,A); 27 A=mul(A,A); 28 n>>=1; 29 } 30 return B; 31 } 32 int main(){ 33 mat A(2,vec(2)); 34 A[0][0]=1;A[0][1]=1; 35 A[1][0]=1;A[1][1]=0; 36 A=pow(A,n); 37 printf("%lld",A[1][0]);//为什么输出这个,按照递推公式得出 38 39 }
http://acm.xidian.edu.cn/problem.php?id=1145
再介绍一题http://acm.hit.edu.cn/hoj/problem/view?id=2255
是哈工大的在线oj上的一个题目,一个类似于斐波那契的题目,题目会给出a,b,p,q,s,e, 其中f(0)=a,f(1)=b,当n>=2时 f(n)=P*f(n-1)+q*f((n-2) 求它组成的数列从第s项起一直加到第e项的和是多少,这题就不能推f(n)的矩阵乘法的递推式了,得推出他的前n项和s(n)的递推式,当然如果会推斐波那契的矩阵形式的递推形式的想必这个就不难了
推理过程如下:
$F\left( N \right) = S\left( N \right) - S\left( {N - 1} \right);$
又有$F\left( N \right) = P*F\left( {N - 1} \right) + Q*F\left( {N - 2} \right)$
所以 $S\left( N \right) - S\left( {N - 1} \right) = P*\left( {S\left( {N - 1} \right) - S\left( {N - 2} \right)} \right) + Q*\left( {S\left( {N - 2} \right) - S\left( {N - 3} \right)} \right)$
$S\left( N \right) = \left( {P + 1} \right)*S\left( {N - 1} \right) + \left( {Q - P} \right)*S\left( {N - 2} \right) - Q*S\left( {N - 3} \right)$
推到这里你应该知道怎么把它化成矩阵乘法的形式了吧?注意到右边有三个S(x)项所以矩阵递推式左边也要有三项写出来就是
化简一下
所以第s项到第e项的和就是S(E)-S(s-1) 注意是S(s-1)
解题方式与上面类似
1 #include<cstdio> 2 #include<cstring> 3 #include<cstdlib> 4 #include<algorithm> 5 using namespace std; 6 typedef long long ll; 7 ll mod=1000000009; 8 struct mat{ 9 ll m[4][4]; 10 }; 11 ll l,r,res1,res2; 12 mat A={ 2,0,0,-1, 13 1,0,0,0, 14 0,1,0,0, 15 0,0,1,0}; 16 mat mul(mat &A,mat &B){ 17 mat C={0}; 18 for(int i=0;i<4;i++){ 19 for(int j=0;j<4;j++){ 20 for(int k=0;k<4;k++){ 21 C.m[i][j]=(C.m[i][j]+A.m[i][k]*B.m[k][j]%mod+mod)%mod; 22 } 23 } 24 } 25 return C; 26 } 27 28 mat mod_pow(mat A,ll n){ 29 mat B={0}; 30 B.m[0][0]=B.m[1][1]=B.m[2][2]=B.m[3][3]=1; 31 while(n>0){ 32 if(n&1) B=mul(B,A); 33 A=mul(A,A); 34 n>>=1; 35 } 36 return B; 37 } 38 39 ll res(mat &a){ 40 return (a.m[3][0]*6+a.m[3][1]*3+a.m[3][2]*2+a.m[3][3])%mod; 41 } 42 43 int main(){ 44 while(scanf("%lld%lld",&l,&r)!=EOF){ 45 if(l==0) res1=0; 46 else{ 47 mat l2=mod_pow(A,l-1); 48 res1=res(l2); 49 } 50 if(r==0) res2=1; 51 else{ 52 mat rr=mod_pow(A,r); 53 res2=res(rr); 54 } 55 ll ans=(res2-res1+mod)%mod; 56 printf("%lld\n",ans); 57 } 58 }