HDU 4549題解 & luogu【模板】矩陣加速(數列)

M斐波那契數列
此題對數學基礎要求較高
來源矩陣乘法_百度百科
一個m*n的矩陣是一個由m行n列元素排成的矩形陣列。矩陣裏的元素可以是數字符號或者數學式.

形如[abcd] 的數表稱爲二階矩陣,其中a,b,c,d稱爲這個矩陣的元素。
形如 [x1x2] 的有序對稱爲列向量

A=[abcd] B=[x1x2]
C=[ax1+bx2ax2+bx1]
稱爲二階矩陣A與平面向量B的乘積,記爲AB=C
更一般的矩陣乘法如下

設A爲m×p 的矩陣,B爲p×n 的矩陣,那麼稱m×n 的矩陣C爲矩陣A與B的乘積,,其中矩陣C中的第i 行第 j 列元素可以表示爲:
這裏寫圖片描述
如下所示:
這裏寫圖片描述

我們知道斐波那契數列的遞推公式f(i)=f(i1)+f(i2)
因此我們可以寫出以下式子
f(i)=1×f(i1)+1×f(i2)
f(i1)=1×f(i1)+0×f(i1)
將每一項的係數寫成一個矩陣
[1110]
由矩陣乘法的特性可知
[f(i)f(i1)]=[1110]×[f(i1)f(i2)]
由此可推出(或找規律)
[f(n)f(n1)]=[1110]n1×[f(1)f(0)]=[1110]n1×[10]

因此只要計算出[1110]n1 ,然後取左上角值就可以了
矩陣定義如下:

struct matrix {
    int n;
    int m;
    long long a[SIZE][SIZE];
    matrix() {
        n=2;
        m=2;
        memset(a,0,sizeof(a));
    }
    matrix(int x,int y) {//構造函數
        n=x;
        m=y;
        memset(a,0,sizeof(a));
    }
    void print() {
        for(int i=1; i<=n; i++) {
            for(int j=1; j<=m; j++) {
                printf("%d ",a[i][j]);
            }
            printf("\n");
        }
    }
    void setv(int x) {//矩陣初始化
        if(x==0) {
            memset(a,0,sizeof(a));
        }
        if(x==1) {
            memset(a,0,sizeof(a));
            for(int i=1; i<=n; i++) a[i][i]=1;
        }
    }
    friend matrix operator *(matrix x,matrix y) {//矩陣乘法
        matrix tmp=matrix(x.m,y.m);
        for(int i=1; i<=x.n; i++) {
            for(int j=1; j<=y.m; j++) {
                tmp.a[i][j]=0;
                for(int k=1; k<=y.n; k++) {
                    tmp.a[i][j]+=(x.a[i][k]*y.a[k][j])%mod;
//                  tmp.a[i][j]%=mod; 取模次數太多會TLE! 
                }
                tmp.a[i][j]%=mod;
            }
        }
        return tmp;
    }
};

矩陣快速冪:
(跟整數的快速冪幾乎一樣)


matrix fast_pow(matrix x,int k) {
    matrix ans=matrix(2,2);
    ans.setv(1);
    while(k>0) {
        if(k&1) {
            ans=ans*x;
        }
        k>>=1;
        x=x*x;
    }
    return ans;  
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章