[JZOJ5736]斐波那契

这篇博客主要探讨如何利用矩阵快速幂算法求解斐波那契数列中,gcd(afn+bfn+1, cfn+dfn+1)的问题。首先介绍了一些gcd的基本性质,然后通过消元法将问题简化为gcd(a'fn+b'fn+1, d'fn+1),进一步借助矩阵乘法计算fn模一个常数的值,并计算gcd(fn, a')。接着,利用gcd的性质将答案转化为gcd(fn+1, a') * gcd(a'fn+b'fn+1, d')的形式,最后只需求解gcd(fn, g*d)和gcd(fn+1, g*d),其中g=gcd(fn+1, a')。博客还特别提醒注意a'和d'为0的特殊情况,整体算法复杂度为O(T*2^3*log(n))。" 118984030,10554546,大二学年学习规划:提升自我,全面发展,"['学习计划', '大二学生', '计算机应用', '奖学金争取', '自我提升']

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

gcd(afn+bfn+1,cfn+dfn+1)gcd(afn+bfn+1,cfn+dfn+1)
首先有几个简单的性质:
gcd(fx,fy)=fgcd(x,y)gcd(fx,fy)=fgcd(x,y)
gcd(a,b)=gcd(akb,b)gcd(a,b)=gcd(a−kb,b)
gcd(b,c)=1gcd(b,c)=1,那么gcd(ab,c)=gcd(a,c)gcd(ab,c)=gcd(a,c)
先通过辗转相除把cc消成0,那么只要考虑gcd(afn+bfn+1,dfn+1)gcd(a′fn+b′fn+1,d′fn+1)
首先通过矩阵乘法我们可以求出fnfn在模一个常数aa下的值,那么就可以求gcd(fn,a)=gcd(fn%a,a)
g=gcd(fn+1,a)g=gcd(fn+1,a′),那么答案就等于ggcd(afn+bfn+1g,dfn+1g)g⋅gcd(a′fn+b′fn+1g,d′fn+1g)
因为gcd(afn+bfn+1g,fn+1g)=1gcd(a′fn+b′fn+1g,fn+1g)=1,那么答案就是ggcd(afn+bfn+1g,d)=gcd(afn+bfn+1,gd)g⋅gcd(a′fn+b′fn+1g,d′)=gcd(a′fn+b′fn+1,g⋅d′)
只需要求出gcd(fn,gd)gcd(fn,g⋅d)gcd(fn+1,gd)gcd(fn+1,g⋅d)即可。
注意特判a=0a′=0d=0d′=0的情况。复杂度O(T23logn)O(T⋅23log⁡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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值