矩陣快速冪演算法+例題(HDU 5667 Sequence)
阿新 • • 發佈:2019-01-20
矩陣快速冪是ACM比賽中對於求遞推式能用到的模板,能實現O(N^3*logM)的複雜度,其中 N是矩陣階乘,M是要求的第幾項。
對於矩陣快速冪,首先的得知道單位矩陣
明顯,單位矩陣與任何矩陣相乘,都會得到那個矩陣,這個就是對矩陣快速冪的時候的基礎矩陣。
然後,我們首先來看看斐波拉契數列
斐波拉契數列的遞推式是Fn = Fn-1 + Fn-2
所以我們可以試著寫出對應的矩陣算式有:
這樣,我們就有:
所以,如果要求出遞推式的那一項,就可以首先根據遞推式寫出遞推矩陣,然後對矩陣進行快速冪,這樣我們就能快速得到我們要求的那一項了,不過,有些題目要求取餘一個mod,這個可以在矩陣懲罰乘法中實現。
最後,我在給出有點廣泛應用的矩陣構造式:
現在,我們來看看這道例題
HDU 5667 Sequence
題目連結
這道題我們簡單分析下就有:
這個求出來只是指數上的,所以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