1. 程式人生 > >矩陣快速冪(模板+例題)

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

模板

#include<cstdio>
#include<cmath>//pow函式,其實沒啥用 
using namespace std;

int n;long long k;
const int N=pow(10,9)+7;
struct node{long long  a[105][105];};
node shu,ans,mp;
//shu是輸入的矩陣,ans是所求答案
node matrix(node x,node y){
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++){
            mp.a[i][j]=0
; for(int p=1;p<=n;p++) mp.a[i][j]=(mp.a[i][j]+x.a[i][p] * y.a[p][j])%N; //矩陣乘法 } return mp; } int work(long long k){//矩陣快速冪 while(k){ if(k&1) ans=matrix(ans,shu); k>>=1; shu=matrix(shu,shu); } } int
main(){ scanf("%d%lld",&n,&k); for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++) scanf("%d",&shu.a[i][j]); ans.a[i][i]=1;//任何一個矩陣乘以單位矩陣,其值等於本身; } work(k); for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++) printf
("%d ",ans.a[i][j]); printf("\n"); } return 0; }

HDU2842(不水)

英文版原題

題目描述:一根木棒上有n個環(n<=10^9) 第一個環可以隨意取下或者放上 如果前k個環都不在棒子上,且第k+1個環在棒子上,則你可以取下或放上第k+2個環 給出n,求最少需要多少步可以取完棒子上的環?

思路:

1.設f[n]陣列表示取下n個環所需最小次數;
2. 若想讓第n個環被取下,那麼前(n-2)個都要被取下,第(n-1)要掛在環上;這時所需次數為f[n-2]+1;
3. 考慮第(n-1)個環還未取下;而取下第(n-1)個環需要第(n-2)個環掛上,取下第(n-2)個環需要第(n-3)個環掛上…即先要把前(n-2個都取下來);還有f[n-1]它自己;以此類推,取下第(n-1)個環需要次數為f[n-2]+f[n-1];
4. 合併得到遞推公式為:f[n] = f[n-1] + 2 * f[n-2] + 1;

題解

座標系

先挖個坑,有些還沒有搞懂

【題目描述】
小澳在座標系的原點,他可以向上、向左或者向右走。他可以走 n 步,但不能經過相同的點。小澳想知道他有多少種走法。

【題解的想法】:
考慮合法路徑的特點,如果第 i-1 步向上走,那麼第 i 步可以向上、左、右走;如果第 i-1 步向左走,那麼第 i 步可以向上或者向左走;如果第 i-1 步向右走,那麼第 i 步可以向上或者向右走。

用 f[i][0]表示走了 i 步,第 i 步向上走的方案數;f[i][1]表示走了 i 步,第 i 步向左走的方案數;f[i][2]表示走了 i 步,第 i 步向右走的方案數,遞推方程:
f[i][0]=f[i-1][0]+f[i-1][1]+f[i-1][2];
f[i][1]=f[i-1][0]+f[i-1][1];
f[i][2]=f[i-1][0]+f[i-1][2];
進行矩陣乘法優化,可以將時間複雜度降低到 O(logn)。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int mod=1e9+7;


struct matrix{
    ll x[2][2];
    matrix(){
        memset(x,0,sizeof(x));//賦0的有效方式 
    }
}ans,a;

matrix operator*(matrix a,matrix b){
    matrix res;
    for(int i=0;i<2;i++){
        for(int j=0;j<2;j++)
            for(int k=0;k<2;k++)
                res.x[i][j]=(res.x[i][j]+a.x[i][k]*b.x[k][j])%mod;
    }
    return res;
}

int main(){
    int n;scanf("%d",&n);n++;
    ans.x[0][0]=1;
    a.x[0][0]=a.x[0][1]=a.x[1][1]=1;
    a.x[1][0]=2;
    for(int i=n;i;i>>=1,a=a*a)
        if(i&1) ans=ans*a;//過載過運算子後要按照規定的用法使用該符號 
    printf("%lld\n",ans.x[0][0]);
    return 0;
}