按部就班,超级简单,虽然不是一次过的。。。错在那个long long数据问题还是要注意。。也不知道要怎么注意;还是说题目吧。。。
思路看main函数
其他函数功能也是非常有用!代码比较丑。。。见谅
#include <stdio.h>
#include <iostream>
#include <sstream>
#include <string.h>
#include <math.h>
#include<stdlib.h>
#include <queue>
#include <set>
#include <algorithm>
using namespace std;
long long mod;
struct asd{
long long a[4][4];
};
asd ak; //代表A的k次
asd mul(asd x,asd y) //矩阵乘法
{
int i,j,k;
asd ans;
for(i=0;i<2;i++)
{
for(j=0;j<2;j++)
{
ans.a[i][j]=0;
for(k=0;k<2;k++)
{
ans.a[i][j]+=(x.a[i][k]*y.a[k][j])%mod;
ans.a[i][j]%=mod;
}
}
}
return ans;
}
asd add(asd x,asd y) //矩阵加法
{
int i,j,k;
asd ans;
for(i=0;i<2;i++)
{
for(j=0;j<2;j++)
{
ans.a[i][j]=(x.a[i][j]+y.a[i][j])%mod;
}
}
return ans;
}
asd quick(asd y,long long g) //快速幂
{
asd x;
int i,k,j;
for(i=0;i<2;i++)
{
for(j=0;j<2;j++)
{
if(i==j)
x.a[i][i]=1;
else
x.a[i][j]=0;
}
}
while(g)
{
if(g%2==1)
x=mul(x,y);
y=mul(y,y);
g/=2;
}
return x;
}
asd slove(long long z) //计算S(n);S(n)代表A的1次加到A的n次;
{
if(z==1)
return ak;
asd ans=slove(z/2);
asd cur;
if(z%2==1)
{
cur=quick(ak,z/2+1);
ans=add(ans,mul(ans,cur));
ans=add(cur,ans);
}
else
{
cur=quick(ak,z/2);
ans=add(ans,mul(ans,cur));
}
return ans;
}
/*反正就想算数一样,斐波那契的那个矩阵肯定知道(不知道出门左转去学一下矩阵快速幂),假设是A,那么也就是题目要求
就是计算A的0+b次到A的k(n-1)+b次的和,次数的相加拆开就是相乘(不知道去复读初中),那么,把A的b次提出来,A^b(E+A^K+A^2K+...A^(n-1)K)
然后把A^K看作整体就是什么!!!还不知道看main函数代码。。草稿纸上列一列就知道了。。。
*/
int main()
{
long long k,b,n;
while(~scanf("%lld%lld%lld%lld",&k,&b,&n,&mod))
{
asd fb,ea,ans,y,sk;
ea.a[0][0]=1;ea.a[0][1]=0; //单位矩阵
ea.a[1][0]=0;ea.a[1][1]=1;
y.a[0][0]=1;y.a[0][1]=1;
y.a[1][0]=1;y.a[1][1]=0;
fb=quick(y,b); //求一个A的b次
ak=quick(y,k); //求一个A的K次
sk=slove(n-1); //求S(K);
sk=add(sk,ea); //把没加的E加上
ans=mul(sk,fb); //乘一波
printf("%lld
",ans.a[0][1]); //这里还是看你的线代怎么样了。。
}
return 0;
}