zoukankan      html  css  js  c++  java
  • [模板]矩阵的快速幂

     原理:

    $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 }
  • 相关阅读:
    Python 入门 之 print带颜色输出
    memcache缓存
    PDO
    面向对象(二)
    面向对象(一)
    文件上传
    简单的权限管理
    当前时间与时期联动
    淡入淡出、滑动、及遍历
    留言板相关功能
  • 原文地址:https://www.cnblogs.com/elpsycongroo/p/6736340.html
Copyright © 2011-2022 走看看