等比数列求和可以二分
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#define LL long long
using namespace std;
LL mod,n,k,b;
//快速幂
struct ma{
LL m[4][4],row,col;
ma()
{
memset(m,0,sizeof(m));
row = col = 0;
}
ma operator * (ma ma1) //乘
{
ma ans;
ans.row = row;
ans.col = ma1.col;
for(int i = 1;i <= ans.row;i++)
for(int j = 1;j <= ans.col;j++)
for(int k = 1;k <= col;k++)
{
ans.m[i][j] += (m[i][k] * ma1.m[k][j]);
ans.m[i][j] %= mod;
}
return ans;
}
ma operator + (ma ma1) //加
{
ma ans;
ans.row = row;
ans.col = col;
for(int i = 1;i <= row;i++)
for(int j = 1;j <= col;j++)
{
ans.m[i][j] = ma1.m[i][j] + m[i][j];
ans.m[i][j] %= mod;
}
return ans;
}
ma operator^(LL n) // 快速幂
{
ma ans,ma1;
ans.row = row; ans.col = col;
ans.m[1][1] = 1;ans.m[1][2] = 0;
ans.m[2][1] = 0;ans.m[2][2] = 1;
// printf("%d\n",n);
// ans.debug();
ma1.row = row; ma1.col = col;
ma1.m[1][1] = m[1][1];ma1.m[1][2] = m[1][2];
ma1.m[2][1] = m[2][1];ma1.m[2][2] = m[2][2];
while(n)
{
if(n&1)ans = ans * ma1;
ma1 = ma1 * ma1;
n >>= 1;
}
return ans;
}
void debug()
{
printf("asda %I64d %I64d\n",row,col);
for(int i = 1;i <= row;i++)
{
for(int j = 1;j <= col;j++)
printf("%I64d ",m[i][j]);
printf("\n");
}
}
}E,mul;
ma bin(ma ma1,LL n) //求 ma^1 到 ma^n 次方的和没有ma^0 主函数还要加个1
{
if(n==1)return ma1;
if(n&1)return (ma1^n) + bin(ma1,n-1); //
else return bin(ma1,n/2) * ((ma1^(n/2)) + E);
}
int main()
{
E.row = 2;E.col = 2;
E.m[1][1] = 1;E.m[1][2] = 0;
E.m[2][1] = 0;E.m[2][2] = 1;
mul.row = 2;mul.col = 2;
mul.m[1][1] = 1;mul.m[1][2] = 1;
mul.m[2][1] = 1;mul.m[2][2] = 0;
while(scanf("%I64d%I64d%I64d%I64d",&k,&b,&n,&mod)!=EOF)
{
ma ma1 = (mul ^ (b));
ma ma2 = (mul ^ (k));
if(n-1>=1)ma2 = bin(ma2,n-1);
ma2 = ma2 + E;
ma ans;
ans.row = 1; ans.col = 2;
ans.m[1][1] = 0, ans.m[1][2] = 1;
ans = (ans*ma1)*ma2;
printf("%I64d\n",ans.m[1][1]);
}
return 0;
}