[JZOJ5736]斐波那契

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(akb,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 消成0,那么只要考虑 gcd(afn+bfn+1,dfn+1) gcd ( a ′ f n + b ′ f n + 1 , d ′ f n + 1 )
首先通过矩阵乘法我们可以求出 fn f n 在模一个常数 a a 下的值,那么就可以求gcd(fn,a)=gcd(fn%a,a)
g=gcd(fn+1,a) g = gcd ( f n + 1 , a ′ ) ,那么答案就等于 ggcd(afn+bfn+1g,dfn+1g) g ⋅ gcd ( a ′ f n + b ′ f n + 1 g , d ′ f n + 1 g )
因为 gcd(afn+bfn+1g,fn+1g)=1 gcd ( a ′ f n + b ′ f n + 1 g , f n + 1 g ) = 1 ,那么答案就是 ggcd(afn+bfn+1g,d)=gcd(afn+bfn+1,gd) g ⋅ gcd ( a ′ f n + b ′ f n + 1 g , d ′ ) = gcd ( a ′ f n + b ′ f n + 1 , g ⋅ d ′ )
只需要求出 gcd(fn,gd) gcd ( f n , g ⋅ d ) gcd(fn+1,gd) gcd ( f n + 1 , g ⋅ d ) 即可。
注意特判 a=0 a ′ = 0 d=0 d ′ = 0 的情况。复杂度 O(T23logn) 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;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值