看着就像是要用矩阵做,但是有个a^b,不知道怎么去推递推式。
思路:对两边取a为底的对数,就可以得到
loga(fn) = c*loga(fn-1) + loga(fn-2) + b,然后令Fn = loga(fn),
可以得到Fn = c*Fn-1 + Fn-2 + b
之后构造矩阵快速幂就行了,得到Fn, fn = a^(Fn), 要mod p,指数
又特别大,所以需要用到费马小定理了(a^x≡a^(x%(p-1))(mod p)).
看到有人说需要加个特判, a是p的倍数时应该输出0。但测试数据没有a事p的倍数,所以
不加也没事。
参考博客:点击打开链接
代码:
#include
using namespace std;
typedef long long ll;
ll n, a, b, c, p;
struct node
{
ll s[3][3];
node() { memset(s, 0, sizeof(s)); }
};
node mul(node a, node b)
{
node t;
for(int i = 0; i < 3; i++)
for(int j = 0; j < 3; j++)
for(int k = 0; k < 3; k++)
t.s[i][j] = (t.s[i][j]+a.s[i][k]*b.s[k][j])%(p-1);
return t;
}
node mt_pow(node p, ll k)
{
node q;
for(int i = 0; i < 3; i++) q.s[i][i] = 1;
while(k)
{
if(k&1) q = mul(p, q);
p = mul(p, p);
k /= 2;
}
return q;
}
ll po(ll x, ll y)
{
ll ans = 1;
while(y)
{
if(y&1) ans = (ans*x)%p;
x = x*x%p;
y /= 2;
}
return ans;
}
int main(void)
{
int t;
cin >> t;
while(t--)
{
scanf("%lld%lld%lld%lld%lld", &n, &a, &b, &c, &p);
if(n == 1) puts("1");
else if(a % p == 0) puts("0");
else
{
node base;
base.s[0][0] = c; base.s[0][1] = 1;
base.s[0][2] = 1; base.s[1][0] = 1;
base.s[2][2] = 1;
node ans = mt_pow(base, n-2);
ll P = (ans.s[0][0]+ans.s[0][2])*b%(p-1);
printf("%lld\n", po(a, P)%p);
}
}
return 0;
}