输出递归因数分解php,关于斐波那契数模意义下的循环节问题

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

找循环节的算法大致是 把模数质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

#include

#include

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;

}

/*

*/

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值