题目描述
定义斐波那契数列F[0]=0, F[1]=1, F[n]=F[n-1]+F[n-2](n>=2)
小猪很喜欢这个数列,她听说你可以求F[n] mod 998244353,觉着很厉害,于是她会进行多次询问,每次询问给出五个整数n,a,b,c,d,她希望你求出gcd(a*F[n]+b*F[n+1],c*F[n]+d*F[n+1]) mod 998244353.
输入
第一个一个正整数q,表示询问数
输出
q行,每行一个[0,998244352]的非负整数,表示询问的答案。
样例输入 Copy
3 1 2 3 5 5 10 5 3 4 2 8 10 6 4 3
样例输出 Copy
5 2 6
提示
数据范围:
对20%的数据,n<=10
对另外10%的数据,b=d=0
对于另外20%的数据,b=c=0
对于100%的数据,1<=q<=100000,1<=n<=1018, 0<=a,b,c,d<=1000, a+b>=1,c+d>=1
预备知识:1. gcd(x, y) = gcd(y, x - ky) (k >= 0)
2. gcd(x, y) = gcd(y, x % y)
3. gcd(f[n], f[n + 1]) = 1
原式:gcd(a * f[n] + b * f[n + 1], c * f[n] + d * f[n + 1])
把d * f[n + 1]去掉
设b = k * d + x
原式 = gcd(a * f[n] + (k * d + x) * f[n + 1], c * f[n] + d * f[n + 1])
= gcd(c * f[n] + d * f[n + 1], (a - c * k) * f[n] + x * f[n + 1]) (根据1知识点)
此时,a' = c, b' = d, c' = a - c * k, d' = x
通过上述继续消除d'f[n + 1],直到d' == 0为止
此时原式 = gcd(a' * f[n] + b' * f[n + 1], c' * f[n])
现在我们考虑几种情况:
1. 如果c' == 0, 原式 = gcd(a' * f[n] + b' * f[n + 1], 0) = a' * f[n] + b' * f[n + 1], 直接矩阵快速幂求出f[n]和f[n + 1]即可
2. 如果b' == 0, 原式 = gcd(a' * f[n], c' * f[n]) = f[n] * gcd(a', c'),f[n]通过矩阵快速幂求出即可
3. c' != 0 && b' != 0 时:
我们来推一个式子
首先 gcd(a' * f[n] + b' * f[n + 1], f[n])
= gcd(b' * f[n + 1], f[n])(根据知识点1)
= gcd(b', f[n]) (根据知识点3)
= gcd(b', f[n] % b') (根据知识点2)
我们令 t = gcd(a' * f[n] + b' * f[n + 1], f[n])
那么 gcd(a' * f[n] + b' * f[n + 1], c' * f[n])
=
= gcd ((a' * f[n] + b' * f[n + 1]) % (t * c'), t * c')
最后直接矩阵快速幂求出f[n]和f[n + 1]即可
注意取模不同,和负数的情况,以及卡常
推荐使用gcd如下
LL gcd(LL a, LL b){
if(a < 0) a =- a;
if(b < 0) b =- b;
if(a && b)
while(a %= b ^= a ^= b ^= a);
return a + b;
}
完整代码:
/**/
#pragma GCC optimize(3,"Ofast","inline")
#include
#include
#include
#include
#include
#include
#include