/*
構造矩陣:
|1 1| | f(2) f(1)|
A= |1 0| = | f(1) f(0)|
|1 1| ^b | f(b+1) f(b)|
A^b =|1 0| = | f(b) f(b-1)|
f(b) = matrix[0][1]=matrix[1][0];
首項是:A^b
公比是:A^k
項數是:N
可以把問題進一步簡化
因爲矩陣的加法對乘法也符合分配律,我們提出一個A^b來,形成這樣的式子:
A^b*( I + A^k + (A^k)^2 + .... + (A^k)^(N-1) )
A^b 和 A^k 顯然都可以用我們之前說過的方法計算出來,這剩下一部分累加怎麼解決呢
設A^k=B
要求 G(N)=I + ... + B^(N-1),
i=N/2
若N爲偶數,G(N)=G(i)+G(i)*B^i = G(i) *( I+B^(i));
若N爲奇數,G(N)=I+ G(i)*B + G(i) * (B^(i+1)) = G(N-1)+B^N; (前一個等式可能要快點,但是後面更簡練)
我們來設置這樣一個矩陣
B I
O I
其中O是零矩陣,I是單位矩陣
將它乘方,得到
B^2 I+B
O I
乘三方,得到
B^3 I+B+B^2
O I
乘四方,得到
B^4 I+B+B^2+B^3
O I
既然已經轉換成矩陣的冪了,繼續用我們的二分或者二進制法,直接求出冪就可以了
*/
#include <cstdio>
int M;
struct Matrix{
__int64 e[2][2];
};
Matrix u,em;
Matrix Mul(Matrix a,Matrix b){
Matrix c;
for(int i=0;i<2;i++){
for(int j=0;j<2;j++){
c.e[i][j]=0;
for(int k=0;k<2;k++){
c.e[i][j]=(c.e[i][j]+a.e[i][k]*b.e[k][j])%M;
}
}
}
return c;
}
Matrix Add(Matrix a,Matrix b){
for(int i=0;i<2;i++)
for(int j=0;j<2;j++)
a.e[i][j]=(a.e[i][j]+b.e[i][j])%M;
return a;
}
Matrix Power(Matrix a,int n){
Matrix t=u;
for(;n;n>>=1,a=Mul(a,a))
if(n&1)
t=Mul(t,a);
return t;
}
Matrix BinarySum(Matrix a,int n){
if(n == 1) return a;
return (n&1)?Add(BinarySum(a,n-1),Power(a,n)):Mul(BinarySum(a,n>>1),Add(Power(a,n>>1),u));
}
void Init(){
u.e[0][0]=1,u.e[0][1]=0,u.e[1][0]=0,u.e[1][1]=1;
em.e[0][0]=1,em.e[0][1]=1,em.e[1][0]=1,em.e[1][1]=0;
}
void Put(Matrix a){
for(int i=0;i<2;i++)
for(int j=0;j<2;j++)
printf("%d\n",a.e[i][j]);
}
int main(){
int k,b,n;
Init();
while(scanf("%d%d%d%d",&k,&b,&n,&M)!=EOF){
Matrix t1,t2,ans;
t1=Power(em,b);
t2=Power(em,k);
ans=Mul(Add(u,BinarySum(t2,n-1)),t1);
printf("%d\n",ans.e[0][1]);
}
return 0;
}
hdu 1588 Gauss Fibonacci
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.