广义Fibonacci数列找循环节

本文介绍了如何通过矩阵幂运算和费马小定理求解广义Fibonacci数列的循环节长度。通过特征值分析和对角化过程,找到最小因子满足特定条件,实现高效计算。

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

转载http://blog.youkuaiyun.com/ACdreamers/article/details/25616461
今天将来学习如何求广义Fibonacci数列的循环节。

问题:给定,满足,求的循
环节长度。

来源:http://acdreamoj.sinaapp.com/ 1075题

分析:我们知道矩阵的递推关系如下

 然后继续有



 那么,现在的问题就转化为求最小的,使得



 所以我们可以先找出符合条件的一个,然后枚举它的因子,找最小的。设



 为了好解决问题,我们需要对矩阵进行相似对角化,即,我们先来求的特征值。



 解得的特征值为



 也就是说的相似对角矩阵为



  因为我们知道,所以当时,, 由于



  继续得到



  设,那么分情况讨论:

   (1)是模的二次剩余,由费马小定理得时,

   (2)是模的二次非剩余,则有



       根据欧拉准则有



       那么继续得到



       然后由费马小定理有,同理有

       所以,当时,

   (3)时,由于不存在,所以无法完成相似对角化,好在这种情况不存在。


  所以综上所述:

  是模的二次剩余时,枚举的因子
  是模的二次非剩余时,枚举的因子

  找最小的因子,使得



  成立。

代码:

#include <iostream>  
#include <string.h>  
#include <algorithm>  
#include <stdio.h>  
#include <math.h>  

using namespace std;  
typedef long long LL;  
const int N = 2;  
const LL MOD = 1000000007;  

LL fac[2][505];  
int cnt,ct;  

LL pri[6] = {2, 3, 7, 109, 167, 500000003};  
LL num[6] = {4, 2, 1, 2, 1, 1};  

struct Matrix  
{  
    LL m[N][N];  
} ;  

Matrix A;  
Matrix I = {1, 0, 0, 1};  

Matrix multi(Matrix a,Matrix b)  
{  
    Matrix c;  
    for(int i=0; i<N; i++)  
    {  
        for(int j=0; j<N; j++)  
        {  
            c.m[i][j]  =0;  
            for(int k=0; k<N; k++)  
            {  
                c.m[i][j] += a.m[i][k] * b.m[k][j];  
                c.m[i][j] %= MOD;  
            }  
        }  
    }  
    return c;  
}  

Matrix power(Matrix A,LL n)  
{  
    Matrix ans = I, p = A;  
    while(n)  
    {  
        if(n & 1)  
        {  
            ans = multi(ans,p);  
            n--;  
        }  
        n >>= 1;  
        p = multi(p,p);  
    }  
    return ans;  
}  

LL quick_mod(LL a,LL b)  
{  
    LL ans = 1;  
    a %= MOD;  
    while(b)  
    {  
        if(b & 1)  
        {  
            ans = ans * a % MOD;  
            b--;  
        }  
        b >>= 1;  
        a = a * a % MOD;  
    }  
    return ans;  
}  

LL Legendre(LL a,LL p)  
{  
    LL t = quick_mod(a,(p-1)>>1);  
    if(t == 1) return 1;  
    return -1;  
}  

void dfs(int dept,LL product = 1)  
{  
    if(dept == cnt)  
    {  
        fac[1][ct++] = product;  
        return;  
    }  
    for(int i=0; i<=num[dept]; i++)  
    {  
        dfs(dept+1,product);  
        product *= pri[dept];  
    }  
}  

bool OK(Matrix A,LL n)  
{  
    Matrix ans = power(A,n);  
    return ans.m[0][0] == 1 && ans.m[0][1] == 0 &&  
           ans.m[1][0] == 0 && ans.m[1][1] == 1;  
}  

int main()  
{  
    fac[0][0] = 1;  
    fac[0][1] = 2;  
    fac[0][2] = 500000003;  
    fac[0][3] = 1000000006;  
    LL a,b,c,d;  
    while(cin>>a>>b>>c>>d)  
    {  
        LL t = a * a + 4 * b;  
        A.m[0][0] = a;  
        A.m[0][1] = b;  
        A.m[1][0] = 1;  
        A.m[1][1] = 0;  
        if(Legendre(t,MOD) == 1)  
        {  
            for(int i=0; i<4; i++)  
            {  
                if(OK(A,fac[0][i]))  
                {  
                    cout<<fac[0][i]<<endl;  
                    break;  
                }  
            }  
        }  
        else  
        {  
            ct = 0;  
            cnt = 6;  
            dfs(0,1);  
            sort(fac[1],fac[1]+ct);  
            for(int i=0;i<ct;i++)  
            {  
                if(OK(A,fac[1][i]))  
                {  
                    cout<<fac[1][i]<<endl;  
                    break;  
                }  
            }  
        }  
    }  
    return 0;  
}  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值