zoukankan      html  css  js  c++  java
  • 【OI】矩阵快速幂

    经过漫长(并不务正业)的暑假,我终于回归了OI。

    下面以此代码为例子:Luogu4910

    #include <cstdio>
    #include <cstring>
    
    typedef long long ll;
    
    const ll MOD = 1000000007;
    
    ll fbi[5][5] = {{1,1,0,0,0},
                     {1,0,0,0,0},
                     {0,0,0,0,0},
                     {0,0,0,0,0},
                     {0,0,0,0,0}
                    };
                    
    ll fir[5][5] = {{1,1,0,0,0},
                     {0,0,0,0,0},
                     {0,0,0,0,0},
                     {0,0,0,0,0},
                     {0,0,0,0,0}
                    };
    
    struct mat{
        ll a[5][5];
        int m,n;//行数,列数 
        
        mat(ll x[5][5],int m1,int n1){
            for(int i = 0 ; i < m1; i ++){
                for(int j = 0 ; j < n1 ; j++){
                    a[i][j] = x[i][j];
                }
            }
            m = m1;
            n = n1;
        }
        mat(int m1, int n1, bool one){
            for(int i = 0; i < m1; i ++){
                for(int j = 0 ; j < n1 ; j++){
                    a[i][j] = 0;
                    if(i == j && one == true) a[i][j] = 1;
                }
            }
            m = m1;
            n = n1;
        }
    };
    
    ll FIB(int N);
    void print(mat a);
    
    mat matmul(mat a,mat b)
    {
    
        if(a.n != b.m) return mat(5,5,false);     
        mat ret(a.m,b.n,false);
        for(int i = 0 ; i < a.m; i ++){
            for(int j = 0; j < b.n; j ++){
                for(int k = 0; k < a.n; k++){
                    ret.a[i][j] += a.a[i][k] * b.a[k][j]; 
                    ret.a[i][j] %= MOD;
                }
            }
        }
        return ret;
    }
    int n;  
    
    mat poww(mat a,int b){
        mat ret(2,2,true);
        while(b){
            if(b&1 == 1) ret = matmul(a,ret);
            a = matmul(a,a);
            b>>=1;
        }
        return ret;
    }
    
    mat calc(int N){
        if(N == 1 || N == 2) return mat(1,2,true);
        mat firmat(fir,1,2);
        mat fb(fbi,2,2);
        mat res = poww(fb,N-1);
        mat ret = matmul(firmat,res);
        return ret;
    }
    
    void print(mat a){
        printf("--------printf--------
    ");
        for(int i = 0 ; i < a.m ; i ++){
            for(int j = 0;  j < a.n; j ++){
                printf("%d ",a.a[i][j]);
            }
            printf("
    ");
        }
        printf("---------end----------
    ");
    }
    
    ll getans(int N){
        if(N == 1) return 2;
        mat M = calc(N-1);
        //print(M);
        return ((M.a[0][1]+M.a[0][0])%MOD+M.a[0][1])%MOD;
        //return FIB(n+1)+FIB(n-1);
    }
    
    int t;
    
    ll FIB(int N){
        ll a = 1;
        ll b = 1;
        if(N < 3) return 1;
        for(int i = 3; i <= N; i++){
            ll tmp = b;
            b = (a+b)%MOD;
            a = tmp;
        }
        return b;
    }
    int main()
    {
        scanf("%d",&t);
        //calc(t);
        for(int i = 0 ; i < t ; i++){
            scanf("%d",&n);
            printf("%lld
    ",getans(n));
        }
        /* test /* 
        n = 1000000000;
        printf("fast:
    ");
        printf("%lld
    ",calc(n));
        printf("slow:
    ");
        printf("%lld
    ",FIB(n));
        */
        
        return 0;
    }

    所谓矩阵快速幂,就是快速幂和矩阵的合体。传统的快速幂是将一个数分为a^1 * a^2 * a^4...,从而进行快速幂计算。而矩阵快速幂,求的是矩阵的幂,由于矩阵乘法也满足类似性质,所以只要给定幂次,再将幂次分解,线性递推出就能矩阵的二的n次幂的幂,用相同于快速幂的方法即可求解。对于一些数论计算和递推题目可以利用矩阵快速幂优化。

  • 相关阅读:
    方法中的散列可变参数
    方法中的散列可变参数
    策略模式
    策略模式
    HashSet,TreeSet
    HashSet,TreeSet
    ArrayList和LinkedList
    ArrayList和LinkedList
    关于鼠标悬浮标签元素效果(CSS:cursor属性)
    关于鼠标悬浮标签元素效果(CSS:cursor属性)
  • 原文地址:https://www.cnblogs.com/dudujerry/p/13693619.html
Copyright © 2011-2022 走看看