1. 程式人生 > >矩陣乘法(乘,遞推,快速冪)學習筆記

矩陣乘法(乘,遞推,快速冪)學習筆記

自己 mod ... 遞推 str class clu 矩陣 快速

矩陣,是一個好東西。

大家都知道,斐波那契數列是滿足如下性質的一個數列:

• f(1) = 1

• f(2) = 1

• f(n) = f(n-1) + f(n-2) (n ≥ 2 且 n 為整數)

題目描述

請你求出 f(n) mod 1000000007 的值。

輸入輸出格式

輸入格式:

·第 1 行:一個整數 n

輸出格式:

第 1 行: f(n) mod 1000000007 的值

輸入輸出樣例

輸入樣例#1:
5
輸出樣例#1:
5
輸入樣例#2:
10
輸出樣例#2:
55

說明

對於 60% 的數據: n ≤ 92

對於 100% 的數據: n在long long(INT64)範圍內。

斐波那契,基礎遞推吧。。但是數據範圍讓線性遞推望而卻步...

這時候,我們列出一個式子:

f(n)=f(n-1)+f(n-2);

f(n)=1*f(n-1)+1*f(n-2);

我們把f(n)和f(n-1):

技術分享圖片

這時發現:

技術分享圖片

於是我們只需要計算

1 1

1 0

的n-1次方就行了。

個人對於矩陣的計算方式一直很迷...看了不少博客,都沒有明白,最後自己總結了一條規律:


第一個矩陣的x行*第二個矩陣的y列,結果相加,作為結果矩陣的(x行,y列)處的數。


矩陣的快速冪:

即使是可以省去大量空間,一次一次推還是會超時...
n-1次方嘛,很容易想到卡速米這個東西。

其實和卡速米一樣,逢二平方即可。

於是上代碼(感覺各個博客,題解的馬蜂都好毒瘤啊。。):

#include<bits/stdc++.h>
using namespace std;
const int mod=1000000007;
long long int n;
struct node
{
    long long int a[3][3];
};
node mul(node x,node y)
{
    node e;
    e.a[1][1
]=e.a[1][2]=e.a[2][1]=e.a[2][2]=0;//初始化矩陣全都是0;for(int i=1;i<=2;i++) { for(int j=1;j<=2;j++) { for(int k=1;k<=2;k++) { e.a[i][j]=(e.a[i][j]+x.a[i][k]*y.a[k][j])%mod;//呱 } } } return e; } node ksm(node x,long long int y) { node ans; ans.a[1][1]=1; ans.a[1][2]=1; ans.a[2][1]=0; ans.a[2][2]=0; while(y) { if(y&1) ans=mul(ans,x); //這裏是要寫成賦值,我居然在這裏卡了好久 x=mul(x,x); y>>=1;//據說位運算能加速然而就快了1ms。。。 } return ans; } int main() { scanf("%lld",&n);//不開longlong見祖宗 node e; e.a[1][1]=e.a[1][2]=e.a[2][1]=1; e.a[2][2]=0;//初始化1110矩陣 if(n==1||n==2)//對n=1,2特判 { printf("1"); return 0; } node ans=ksm(e,n-2);//卡速米真好吃 printf("%lld",ans.a[1][1]); return 0; }

(完)



矩陣乘法(乘,遞推,快速冪)學習筆記