这个题目感觉是比较综合的一个题目了,这个用了好几个公式,很值得记住啊。
一开始在之前遇到了一个斐波那契数列的问题如下:
•eg.求斐波那契数列第n项(n<=10^18)
•f[0]=0,f[1]=1,f[i]=f[i-1]+f[i-2](i>=2)
这个题目的求解的话,就是建立一个矩阵的递推式,然后矩阵快速幂就可以轻松解出来的。
这个就是一般的对斐波那契数列的推导,其中那个2*2的矩阵暂记A。
然后还有一个对斐波那契数列的推导方法,如下所示:
然后这个公式就可以拿来解决这个题目了,这个题目求的是对g函数代入就相当于是
f[b]+f[k+b]+f[2*k+b]+...+f[k*(n-1)+b]
然后这个式子的求解就可以看成是A^b+A^(k+b)+A^(2*k+b)+...+A^(k*(n-1)+b)这个求出来的就相当于是上面的那个2*2的矩阵的结果了,然后要取得就是这个矩阵的第一行第二列的f的值即可。这样就求出来了累加的
f[b]+f[k+b]+f[2*k+b]+...+f[k*(n-1)+b]值了。
下面的就是求解
A^b+A^(k+b)+A^(2*k+b)+...+A^(k*(n-1)+b)的问题了。
求解这个可以先提取了A^b这个矩阵后形成了
A^b * ( A^0 + A^k + A^(2*k) + ... + A^((n-1)*k) )
再可以化简成
A^b * ( (A^k)^0 + (A^k)^1 + (A^k)^2 + ...+ (A^k)^(n-1) )
然后把A^k看成是一个矩阵P即可,就成了
求A^b和求(E+P+P^2+...+P^(n-1)),前面直接矩阵快速幂,然后后面的这个就是前一篇博客写到的这个求解的问题了。见前面的博客:http://blog.youkuaiyun.com/qq_23702679/article/details/52770942 点击打开链接
最后这个问题就解决了,感觉真的是蛮综合的问题的啊,解决起来根本是想不到,只是在第一个斐波那契序列的递推式那里在琢磨,根本没有想到这个第二的这种递推式子,看起来对于矩阵的递推式子的积累还是很重要的啊。
贴上代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
int k,b,n,m;
struct Mat
{
long long int sm[3][3];
}A,E,zero;
struct superMat
{
Mat sm[3][3];
}MA,ME;
void init()
{
A.sm[0][0]=A.sm[0][1]=A.sm[1][0]=1;A.sm[1][1]=0;
E.sm[0][0]=E.sm[1][1]=1;E.sm[0][1]=E.sm[1][0]=0;
zero.sm[0][0]=zero.sm[0][1]=zero.sm[1][0]=zero.sm[1][1]=0;
ME.sm[0][0]=ME.sm[1][1]=E;
ME.sm[0][1]=ME.sm[1][0]=zero;
}
Mat mul(Mat a,Mat b)
{
Mat tmp;
for(int i=0;i<2;i++)
{
for(int j=0;j<2;j++)
{
tmp.sm[i][j]=0;
for(int k=0;k<2;k++)
{
tmp.sm[i][j]=(tmp.sm[i][j]+(a.sm[i][k]*b.sm[k][j])%m)%m;
}
}
}
return tmp;
}
Mat getMat(Mat a,int k)
{
Mat tmp;
Mat x,y,z;
x=A;
y=E;
for(;k;k>>=1)
{
if(k&1)
y=mul(x,y);
x=mul(x,x);
}
return y;
}
Mat add(Mat a,Mat b)
{
Mat tmp;
for(int i=0;i<2;i++)
{
for(int j=0;j<2;j++)
{
tmp.sm[i][j]=(a.sm[i][j]+b.sm[i][j])%m;
}
}
return tmp;
}
superMat supermul(superMat x,superMat y)
{
superMat tmp;
for(int i=0;i<2;i++)
{
for(int j=0;j<2;j++)
{
tmp.sm[i][j]=zero;
for(int k=0;k<2;k++)
{
tmp.sm[i][j]=add(tmp.sm[i][j],mul(x.sm[i][k],y.sm[k][j]));
}
}
}
return tmp;
}
superMat getsuperMat(int n)
{
superMat x,y,z;
x=MA;
y=ME;
for(;n;n>>=1)
{
if(n&1)
y=supermul(x,y);
x=supermul(x,x);
}
return y;
}
int main()
{
while(scanf("%d%d%d%d",&k,&b,&n,&m)!=EOF)
{
init();
Mat Fb=getMat(A,b);
Mat K=getMat(A,k);
MA.sm[0][0]=K;
MA.sm[0][1]=MA.sm[1][1]=E;
MA.sm[1][0]=zero;
superMat Q=getsuperMat(n);
Mat z=Q.sm[0][1];
Mat r=mul(z,Fb);
printf("%lld\n",r.sm[0][1]);
}
return 0;
}