关于斐波那契数模意义下的循环节问题

123456

\(f(f(n))\)\(f\)表示斐波那契数
\(n\leq10^{100}\)
对于\(1e9+7\)取mod
斐波那契数在mod意义下是有循环节的,
然后zhx把他出在了noip模拟题里,
丧心病狂,

丢一个paper
Charles W. Campbell II. The Period of the Fibonacci Sequence Modulo j. 2007.

找循环节的算法大致是
把模数质n因数分解,分解为$ p_1 ^ {k_1} * p_2^ {k_2} *...p_n^{k_n} $
对于%n意义下的循环节就是$ lcm (mod (质因数 ^ k) 意义下的循环节 ) $
那么后面那个怎么求呢
有定理

\(fib数 mod p^m\) 的最小循环节长度为 \(G(p) * p^{m - 1}\)其中,\(G(p)\)表示\(%p\)的最小循环节长度

现在就是求\(G(p)\)
对于\(G(p)\)我们有如下定理

如果\(5\)是模\(p\)的二次剩余那么循环节的长度是\(p-1\)的因子否则长度为\(2(p + 1)\)
二次剩余及计算方法
对于小于等于5的素数特殊判断,loop(2)=3,loop(3)=8,loop(5)=20。

可以求出所有的因子,然后用矩阵快速幂来一个一个判断,这样时间复杂度不会很大。

本题模数只有一个,手玩就好了

代码

#include<cstdio> 
#include<cstring> 
#include<algorithm> 

using namespace std; 
#define int long long 
inline int read() { 
    int x = 0,f = 1; 
    char c = getchar(); 
    while(c  < '0' || c > '9') c = getchar(); 
    while(c  <= '9' && c >= '0') x = x * 10 + c-'0',c = getchar(); 
    return x *f ; 
} 
const int m1 = 1000000007; 
const int m2 = m1 * 2 + 2; 
const int m3 = m2 * 3; 
int n ; 
struct Matrix { 
    int a[3][3]; 
    Matrix () { memset(a,0,sizeof a); }     
    Matrix  operator * (const Matrix & p) const { 
        Matrix ret; 
        for(int i = 0;i <= 1;++ i) 
            for(int j = 0;j <= 1;++ j) 
                for(int k = 0;k <= 1;++ k) 
                    ret.a[i][j] = (ret.a[i][j] + a[i][k] * p.a[k][j]) % m1; 
        return ret; 
    } 
    Matrix  operator + (const Matrix & p) const {
        Matrix ret; 
        for(int i = 0;i <= 1;++ i) 
            for(int j = 0;j <= 1;++ j) 
                for(int k = 0;k <= 1;++ k) 
                    ret.a[i][j] =(ret.a[i][j] +  a[i][k] * p.a[k][j]) % m2; 
        return ret; 
    } 
}; 
int get1(int x) { 
    Matrix p,q; 
    p.a[0][0] = 1; p.a[0][1] = 1; p.a[1][0] = 1; 
    q.a[0][1] = 1;//,q.a[1][1] = 1; 
    for(;x;x >>= 1,p = p + p) 
        if(x & 1) q = q + p; 
    return q.a[0][0]; 
} 
int get2(int x) { 
    Matrix p,q; 
    p.a[0][0] = 1; p.a[0][1] = 1; p.a[1][0] = 1; 
    q.a[0][1] = 1;  
    for(;x;x >>= 1,p = p * p) 
        if(x & 1) q = q * p; 
    return q.a[0][0]; 
} 
char s[100007]; 
struct bign { 
    int z[100007],l;
    void init() { 
        memset(z,0,sizeof(z)); 
        scanf("%s",s + 1); 
        l = strlen(s + 1); 
        for(int i = 1;i <= l;i ++) 
            z[i] = s[l - i + 1] - '0'; 
    } 
    int operator % (const long long & a) const { 
        int b = 0; 
        for (int i = l;i >= 1;i --) 
            b = (b * 10 + z[i]) % a; 
        return b; 
    } 
}z;  
main() { 
    int t = read(); 
    bign num; 
    while(t --)  { 
        num.init(); 
        n = num % m3; 
        n = get1(n); 
        printf("%lld\n",get2(n));  
    }   
    return 0; 
} 
/* 

*/ 

转载于:https://www.cnblogs.com/sssy/p/9418732.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值