时间限制: 1 Sec 内存限制: 128 MB
题目描述
定义斐波那契数列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 <cstdio>
#include <cstring>
#include <cmath>
#include <cctype>
#include <iostream>
#include <algorithm>
#include <map>
#include <set>
#include <vector>
#include <string>
#include <stack>
#include <queue>
typedef long long LL;
using namespace std;
const long long mod = 998244353;
int t, a, b, c, d;
LL n;
int Fib(LL n, LL mod){
if(n <= 1) return n % mod;
n--;
int a[2][2] = {1, 1, 1, 0};
int res[2][2] = {1, 0, 0, 1};
LL c[2][2];
while(n){
if(n & 1){
for (int i = 0; i < 2; i++){
for (int j = 0; j < 2; j++){
c[i][j] = (LL)res[i][0] * a[0][j] + (LL)res[i][1] * a[1][j];
}
}
for (int i = 0; i < 2; i++){
for (int j = 0; j < 2; j++){
res[i][j] = c[i][j] % mod;
}
}
}
for (int i = 0; i < 2; i++){
for (int j = 0; j < 2; j++){
c[i][j] = (LL)a[i][0] * a[0][j] + (LL)a[i][1] * a[1][j];
}
}
for (int i = 0; i < 2; i++){
for (int j = 0; j < 2; j++){
a[i][j] = c[i][j] % mod;
}
}
n >>= 1;
}
return res[0][0];
}
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;
}
int main()
{
//freopen("in.txt", "r", stdin);
//freopen("out.txt", "w", stdout);
scanf("%d", &t);
while(t--){
scanf("%lld %d %d %d %d", &n, &a, &b, &c, &d);
while(d){
int tmp = b / d;
b -= d * tmp;
a -= c * tmp;
swap(b, d);
swap(a, c);
}
// printf("%d %d %d %d\n", a, b, c, d);
int res = c < 0 ? -c : c;
if(!c){
printf("%lld\n", (1LL * Fib(n, mod) * a % mod + 1LL * Fib(n + 1, mod) * b % mod + mod) % mod);
continue;
}
if(!b){
printf("%lld\n", 1LL * Fib(n, mod) * gcd(a, c) % mod);
continue;
}
res *= gcd(Fib(n, b), b);
printf("%lld\n", gcd(1LL * res, 1LL * Fib(n, res) * a + 1LL * Fib(n + 1, res) * b) % mod);
}
return 0;
}
/**/
本文深入探讨了斐波那契数列的性质及其应用,特别是在求解特定数学问题时如何利用矩阵快速幂算法高效计算。文章详细解释了如何处理涉及斐波那契数列的复杂表达式的求值,包括模运算和最大公约数计算,为读者提供了理解和解决此类问题的清晰路径。
2947

被折叠的 条评论
为什么被折叠?



