求
gcd(afn+bfn+1,cfn+dfn+1)
gcd
(
a
f
n
+
b
f
n
+
1
,
c
f
n
+
d
f
n
+
1
)
。
首先有几个简单的性质:
gcd(fx,fy)=fgcd(x,y)
gcd
(
f
x
,
f
y
)
=
f
g
c
d
(
x
,
y
)
gcd(a,b)=gcd(a−kb,b)
gcd
(
a
,
b
)
=
gcd
(
a
−
k
b
,
b
)
若
gcd(b,c)=1
gcd
(
b
,
c
)
=
1
,那么
gcd(ab,c)=gcd(a,c)
gcd
(
a
b
,
c
)
=
gcd
(
a
,
c
)
。
先通过辗转相除把
c
c
消成,那么只要考虑
gcd(a′fn+b′fn+1,d′fn+1)
gcd
(
a
′
f
n
+
b
′
f
n
+
1
,
d
′
f
n
+
1
)
首先通过矩阵乘法我们可以求出
fn
f
n
在模一个常数
a
a
下的值,那么就可以求。
设
g=gcd(fn+1,a′)
g
=
gcd
(
f
n
+
1
,
a
′
)
,那么答案就等于
g⋅gcd(a′fn+b′fn+1g,d′fn+1g)
g
⋅
gcd
(
a
′
f
n
+
b
′
f
n
+
1
g
,
d
′
f
n
+
1
g
)
。
因为
gcd(a′fn+b′fn+1g,fn+1g)=1
gcd
(
a
′
f
n
+
b
′
f
n
+
1
g
,
f
n
+
1
g
)
=
1
,那么答案就是
g⋅gcd(a′fn+b′fn+1g,d′)=gcd(a′fn+b′fn+1,g⋅d′)
g
⋅
gcd
(
a
′
f
n
+
b
′
f
n
+
1
g
,
d
′
)
=
gcd
(
a
′
f
n
+
b
′
f
n
+
1
,
g
⋅
d
′
)
。
只需要求出
gcd(fn,g⋅d)
gcd
(
f
n
,
g
⋅
d
)
和
gcd(fn+1,g⋅d)
gcd
(
f
n
+
1
,
g
⋅
d
)
即可。
注意特判
a′=0
a
′
=
0
和
d′=0
d
′
=
0
的情况。复杂度
O(T⋅23logn)
O
(
T
⋅
2
3
log
n
)
。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long
#define up(x,y) (x=(x+(y))%mod)
#define abs(x) (x<0?-(x):x)
using namespace std;
const int MOD=998244353;
int mod;
ll gcd(ll a,ll b)
{
if(!b) return a;
return gcd(b,a%b);
}
ll f[12];
struct matrix
{
int h,w;
ll a[2][2];
matrix(int hx,int wx){memset(a,0,sizeof(a));h=hx;w=wx;}
matrix operator *(matrix b)
{
matrix re(h,b.w);
for(int i=0;i<h;i++)
for(int j=0;j<b.w;j++)
for(int k=0;k<w;k++)
up(re.a[i][j],a[i][k]*b.a[k][j]);
return re;
}
}mf(2,2);
matrix ksm(matrix a,ll b)
{
matrix re(a.h,a.w);
for(int i=0;i<a.h;i++)
re.a[i][i]=1;
for(;b;b>>=1)
{
if(b&1) re=re*a;
a=a*a;
}
return re;
}
ll getf(ll k,int m)
{
mod=m;
matrix r=ksm(mf,k);
return r.a[1][0];
}
int main()
{
int ca;
scanf("%d",&ca);
mf.a[0][0]=mf.a[1][0]=mf.a[0][1]=1;
while(ca--)
{
ll n,a,b,c,d;
scanf("%lld%lld%lld%lld%lld",&n,&a,&b,&c,&d);
while(c)
{
b-=(a/c)*d;a%=c;
if(a<c) swap(a,c),swap(b,d);
}
if(!a){printf("%lld\n",getf(n+1,MOD)*gcd(b,d)%MOD);continue;}
if(!d){printf("%lld\n",(getf(n,MOD)*a%MOD+getf(n+1,MOD)*b%MOD+MOD+MOD)%MOD);continue;}
ll g=gcd(getf(n+1,a),a),ans=gcd(a*getf(n,g*d)+b*getf(n+1,g*d),g*d);
printf("%lld\n",abs(ans)%MOD);
}
return 0;
}