hdu 1588 Gauss Fibonacci

/*
構造矩陣:
	   |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;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章