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;
}
/*
*/