Gauss Fibonacci


Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 2400    Accepted Submission(s): 1003

Problem Description


Without expecting, Angel replied quickly.She says: "I'v heard that you'r a very clever boy. So if you wanna me be your GF, you should solve the problem called GF~. "
How good an opportunity that Gardon can not give up! The "Problem GF" told by Angel is actually "Gauss Fibonacci".
As we know ,Gauss is the famous mathematician who worked out the sum from 1 to 100 very quickly, and Fibonacci is the crazy man who invented some numbers.

Arithmetic progression:
g(i)=k*i+b;
We assume k and b are both non-nagetive integers.

Fibonacci Numbers:
f(0)=0
f(1)=1
f(n)=f(n-1)+f(n-2) (n>=2)

The Gauss Fibonacci problem is described as follows:
Given k,b,n ,calculate the sum of every f(g(i)) for 0<=i<n
The answer may be very large, so you should divide this answer by M and just output the remainder instead.



Input


The input contains serveral lines. For each line there are four non-nagetive integers: k,b,n,M
Each of them will not exceed 1,000,000,000.


 


Output


For each line input, out the value described above.


 


Sample Input


2 1 4 100 2 0 4 100


 


Sample Output


21 12


HDU 1588 Gauss Fibonacci 斐波那契矩阵+等比矩阵二分求和_HDU

等比矩阵二分求和

偶数:

HDU 1588 Gauss Fibonacci 斐波那契矩阵+等比矩阵二分求和_ci_02

奇数:

HDU 1588 Gauss Fibonacci 斐波那契矩阵+等比矩阵二分求和_1588_03

/*
HDU 1588 斐波那契矩阵
题意:g(i)=k*i+b,sum(f(g(i)) for 0<=i<n

斐波那契数列转化为矩阵:
A={1 1}
{1,0};
{f[n+1],f[n]}
{f[n],f[n-1]}=A^n;最后输出右上角那项
根据Fibonacci矩阵的求法,f(i)=mat^i 令mat={1,1,1,0}(二阶矩阵)

f(g(i))=mat^g(i)=mat^(ki+b)
sum(f(g(i))=mat^b+mat^(k+b)+...+mat^(ki+b) for 0<=i<n
提取mat^b得:
sum(f(g(i))=mat^b+mat^b[mat^(k)+mat^2k...+mat^(ki)]

mat^(k)+mat^2k...+mat^(ki)
对等比矩阵进行二分求和,做法如下:
求得matk=mat^k
原式=matk+matk^2+...+matk^i
如果i为偶数:原式=(matk+matk^2+...+matk^(i/2))+matk^(i/2)(matk+matk^2+...+matk^i/2)
=(1+matk^(i/2))S_i/2
如果i为奇数:那我们干脆先计算前面的i-1个偶数
用前面所诉的方法 tmp1=matk+matk^2+...+matk^i/2 tmp2=tmp1*matk^i/2
前偶数个的和tmp=tmp1+tmp2 最后的结果=tmp+matk^i

sum(f(g(i))=mat^b+mat^b[mat^(k)+mat^2k...+mat^(ki)]
*/
#include<iostream>
#include<stdio.h>
using namespace std;
typedef __int64 LL;
struct matrix{
LL map[2][2];
};
matrix mat,matk,matb,matSum;
int k,b,n,M;

void init()//初始化
{
int i,j;
mat.map[0][0]=1;
mat.map[0][1]=1;
mat.map[1][0]=1;
mat.map[1][1]=0;
}

matrix mul(matrix a,matrix b)//矩阵乘法
{
int i,j,k;
matrix c;
for(i=0;i<2;i++)
for(j=0;j<2;j++)
{
c.map[i][j]=0;
for(k=0;k<2;k++)
c.map[i][j]+=a.map[i][k]*b.map[k][j];
c.map[i][j]%=M;
}
return c;
}

matrix matPow(matrix ma,int n)//快速幂
{
matrix ans;
int i,j;
for(i=0;i<2;i++)//建立一个单元阵 保存结果
for(j=0;j<2;j++)
ans.map[i][j]=(i==j);

for(;n;n>>=1)
{
if(n&1)
ans=mul(ans,ma);
ma=mul(ma,ma);
}
return ans;
}

matrix matAdd(matrix a,matrix b)//矩阵加法
{
matrix c;
int i,j;
for(i=0;i<2;i++)
for(j=0;j<2;j++)
{
c.map[i][j]=a.map[i][j]+b.map[i][j];
c.map[i][j]%=M;
}
return c;
}

matrix binarySum(int k)//等比数列二分求和
{
if(k==1)
return matk;
else if(k&1)
return matAdd(binarySum(k-1),matPow(matk,k));//就是偶数+最后个matk^(k)
else
{
matrix tmp1=binarySum(k>>1);//S_n/2
matrix tmp2=mul(matPow(matk,k>>1),tmp1);//Sn/2*matk^(k/2)
return matAdd(tmp1,tmp2);//S_n/2*matk^(k/2)+S_n/2
}
}

int main()
{
int i,j;

init();
while(scanf("%d%d%d%d",&k,&b,&n,&M)!=EOF)
{
matk=matPow(mat,k);//求mat^k;
matSum=binarySum(n-1);//求matk的等比数列的前n-1项和 i<n
if(b)
{
matb=matPow(mat,b);//mat^b
matSum=mul(matb,matSum);//sum=sum*matb;
matSum=matAdd(matb,matSum);//sum+=matb;
}
printf("%I64d\n",matSum.map[1][0]);
}
return 0;
}