1. 程式人生 > >矩陣快速冪演算法+例題(HDU 5667 Sequence)

矩陣快速冪演算法+例題(HDU 5667 Sequence)

矩陣快速冪是ACM比賽中對於求遞推式能用到的模板,能實現O(N^3*logM)的複雜度,其中 N是矩陣階乘,M是要求的第幾項。

對於矩陣快速冪,首先的得知道單位矩陣

111100101
明顯,單位矩陣與任何矩陣相乘,都會得到那個矩陣,這個就是對矩陣快速冪的時候的基礎矩陣。
然後,我們首先來看看斐波拉契數列
斐波拉契數列的遞推式是Fn = Fn-1 + Fn-2
所以我們可以試著寫出對應的矩陣算式有:
{An+1An}={1110}{AnAn1}
這樣,我們就有:
{AnAn1}={1110}n{11}
所以,如果要求出遞推式的那一項,就可以首先根據遞推式寫出遞推矩陣,然後對矩陣進行快速冪,這樣我們就能快速得到我們要求的那一項了,不過,有些題目要求取餘一個mod,這個可以在矩陣懲罰乘法中實現。

最後,我在給出有點廣泛應用的矩陣構造式:

f(x)=i=0m1BiAn+i
An+mAn+m1An=Bm1100B11B000An+m1An+m2An

現在,我們來看看這道例題

HDU 5667 Sequence

題目連結
這道題我們簡單分析下就有:

An+1An1=c10100b01AnAn11(n>=2)
這個求出來只是指數上的,所以mod p的時候得 mod p-1(因為p是質數),然後對a快速冪,這時候就mod p就能得到答案了。
#include <cstdio>
#include <iostream> #include <cstring> #include <algorithm> #include <cmath> using namespace std; #define LL long long LL p,aa,bb,cc,n,mod; //mod為p-1 struct matrix { LL mat[3][3]; }; matrix pow1(matrix a,matrix b) // N^3的矩陣相乘 { matrix c; memset(c.mat,0,sizeof(c.mat)); for
(int i=0;i<3;i++){ for(int j=0;j<3;j++){ for(int k=0;k<3;k++){ c.mat[i][j] += (a.mat[i][k]*b.mat[k][j]); c.mat[i][j] %= mod; } } } return c; } matrix cheng(matrix a,LL y) //矩陣快速冪 { matrix b; memset(b.mat,0,sizeof(b.mat)); for(int i=0;i<3;i++) b.mat[i][i] = 1; while(y){ if(y&1){ b = pow1(a,b); y-=1; }else { a = pow1(a,a); y/=2; } } return b; } LL quick_pow(LL a,LL tmp) //對a進行快速冪 { LL b = 1ll; while(tmp) { if(tmp&1) b=(a*b)%p; a=(a*a)%p; tmp>>=1; } return b; } int main() { int t; scanf("%d",&t); while(t--){ scanf("%lld%lld%lld%lld%lld",&n,&aa,&b