[模板]矩阵的快速幂

 原理:

$left( {egin{array}{*{20}{c}}
{{F_{n + 2}}}\
{{F_{n + 1}}}
end{array}} ight) = left( {egin{array}{*{20}{c}}
1&1\
1&0
end{array}} ight)left( egin{array}{l}
{F_{{ m{n + }}1}}\
{F_n}
end{array} ight)$

 记这个矩阵为A,则有

$left( {egin{array}{*{20}{c}}
{{F_{n + 1}}}\
{{F_n}}
end{array}} ight) = {A^n}left( egin{array}{l}
{F_1}\
{F_0}
end{array} ight)$

注意这种初始化方式,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
",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)的递推式,当然如果会推斐波那契的矩阵形式的递推形式的想必这个就不难了

推理过程如下:

$Fleft( N ight) = Sleft( N ight) - Sleft( {N - 1} ight);$

又有$Fleft( N ight) = P*Fleft( {N - 1} ight) + Q*Fleft( {N - 2} ight)$

所以 $Sleft( N ight) - Sleft( {N - 1} ight) = P*left( {Sleft( {N - 1} ight) - Sleft( {N - 2} ight)} ight) + Q*left( {Sleft( {N - 2} ight) - Sleft( {N - 3} ight)} ight)$

$Sleft( N ight) = left( {P + 1} ight)*Sleft( {N - 1} ight) + left( {Q - P} ight)*Sleft( {N - 2} ight) - Q*Sleft( {N - 3} ight)$

推到这里你应该知道怎么把它化成矩阵乘法的形式了吧?注意到右边有三个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
",ans);
57     }
58 }
原文地址:https://www.cnblogs.com/elpsycongroo/p/6736340.html