矩陣快速冪模板+例題(快速入門)

矩陣快速冪模板+例題(快速入門)

本來早在一個月前就應該把這給掌握的,硬是得等到卡題了,纔想到來補知識

文章目錄

模板

傳送門:矩陣快速冪基礎講解

單純的求某一矩陣的快速冪是沒有什麼意義的,主要是由於所求的遞推式的數比較大時,如果使用暴力遞推,必定會超時,這時矩陣快速冪的作用就完美體現了

根據個人碼風和編碼習慣,敲了一份模板,如果覺得有用,大佬們不妨留個讚唄(手動滑稽)

/*
 *  矩陣快速冪 n*n矩陣的x次冪
 */
#include<cstdio>
#include<iostream>
#include<cstring>
#define ll long long
#define mod 9973
using namespace std;
int n,x;
const int maxn=15;
struct mat{
    ll m[maxn][maxn];
    mat(){
        memset(m,0,sizeof(m));
    }
    //重載矩陣乘法
    mat operator * (const mat b)const{
        mat ans;
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                for(int k=1;k<=n;k++){
                    ans.m[i][j]+=m[i][k]*b.m[k][j];
                    ans.m[i][j]%=mod;
                }
            }
        }
        return ans;
    }
};
//矩陣快速冪
mat pow_mat(mat a,int b){
mat ans;
//初始化爲單位矩陣
    for(int i=1;i<=n;i++){
        ans.m[i][i]=1;
    }
    while(b){
        if(b&1){
            ans=ans*a;
        }
        a=a*a;
        b>>=1;
    }
    return ans;
}
int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        scanf("%d%d",&n,&x);
        mat a;
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                scanf("%lld",&a.m[i][j]);
            }
        }
        a=pow_mat(a,x);
        //輸出矩陣
        /*
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                cout<<a.m[i][j]<<" ";
            }
            cout<<endl;
        }*/
        ll sum=0;
        for(int i=1;i<=n;i++){
            sum=(sum+a.m[i][i])%mod;
        }
        printf("%lld\n",sum);
    }
    return 0;
}

例題

一、HDU 1575:Tr A

題目鏈接

題目大意:
題意也是很簡單,畢竟是模板題嘛;求某一矩陣a的k次冪,之後求矩陣對角線的和取模

代碼:
剛剛我的模板恰好是解決這一題的完整代碼

二、POJ 3070:Fibonacci

題目鏈接

題目大意:
求最經典的斐波拉契數列f[n],但由於n比較大,如果我們直接使用遞歸的話會超時,但是我們選擇用數組存的話,內存肯定會超限(因爲n過於大)

這時就得想到矩陣快速冪了
在這裏插入圖片描述
代碼:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cstring>
#define inf 0x3f3f3f3f
#define mod 10000
#define ll long long
using namespace std;
const double eps=1e-6;
const int maxn=5;
ll n,x;
struct mat{
    ll m[maxn][maxn];
    mat(){
        memset(m,0,sizeof(m));
    }
    mat operator * (const mat b)const{
        mat ans;
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                for(int k=1;k<=n;k++){
                    ans.m[i][j]+=m[i][k]*b.m[k][j];
                    ans.m[i][j]%=mod;
                }
            }
        }
        return ans;
    }
};
mat pow_mat(mat a,int b){
    mat ans;
    for(int i=1;i<=n;i++){
        ans.m[i][i]=1;
    }
    while(b){
        if(b&1){
            ans=ans*a;
        }
        a=a*a;
        b>>=1;
    }
    return ans;
}
int main(){
    n=2;
    while(~scanf("%lld",&x)){
        if(x==-1)
            break;
        mat a;
        a.m[1][1]=1,a.m[1][2]=1;
        a.m[2][1]=1,a.m[2][2]=0;
        a=pow_mat(a,x);
        printf("%lld\n",a.m[1][2]);
    }
    return 0;
}

三、HNUCM 1620: Fy’s dota2

題目鏈接

題目大意:
很明顯能夠得到遞推公式:
在這裏插入圖片描述
由於所求的數列下標比較大,於是用到快速冪,構造矩陣
在這裏插入圖片描述
代碼:

#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
#define mod 7777777
#define ll long long
using namespace std;
const double eps=1e-6;
const int maxn=15;
int n,x;
struct mat{
    ll m[maxn][maxn];
    mat(){
        memset(m,0,sizeof(m));
    }
    //重載矩陣乘法
    mat operator * (const mat b)const{
        mat ans;
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                for(int k=1;k<=n;k++){
                    ans.m[i][j]+=m[i][k]*b.m[k][j];
                    ans.m[i][j]%=mod;
                }
            }
        }
        return ans;
    }
};
//矩陣快速冪
mat pow_mat(mat a,int b){
    mat ans;
    for(int i=1;i<=n;i++){
        ans.m[1][i]=pow(2,n-i);
    }
    while(b){
        if(b&1){
            ans=ans*a;
        }
        a=a*a;
        b>>=1;
    }
    return ans;
}
int main(){
    scanf("%d%d",&n,&x);
    if(n>=x){
        printf("%d\n",(int)pow(2,x-1));
    }
    else{
        mat a;
        for(int i=1;i<=n;i++){
            a.m[i][1]=1;
            a.m[i][i+1]=1;
        }
        a=pow_mat(a,x-n);
        printf("%lld\n",a.m[1][1]);
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章