/*
构造矩阵:
|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
最新推荐文章于 2020-09-05 07:25:00 发布