题意
求斐波那契数列第 n n n项和第 m m m项的最大公约数( n , m ≤ 2 × 1 0 9 n,m \leq 2 \times 10^9 n,m≤2×109)
题解
数据范围明确表明这题不是找规律就是推奇怪的结论。
于是先开始找规律。假设 f ( x ) f(x) f(x)表示有x因子的数在斐波那契数列中出现的循环节长度。之所以这么说是因为打表发现拥有某个因子的数非常有规律,比如 2 2 2(被 2 2 2整除记为 Y Y Y,反之 N N N): N N Y    N N Y    N N Y    N N Y    N N Y ⋯ NNY \; NNY \; NNY \; NNY \; NNY \cdots NNYNNYNNYNNYNNY⋯。然后 f ( x ) f(x) f(x)还是积性函数。于是问题变成了求 f ( x ) f(x) f(x)是 n n n和 m m m的公约数的最大的 x x x。
但是这有什么用呢?
然后我开始试图推结论。假设 n ≤ m n \leq m n≤m,于是 f b ( m ) fb(m) fb(m)可以表示为 f b ( m − n ) × f b ( n − 1 ) + f b ( m − n + 1 ) × f b ( n ) fb(m-n) \times fb(n-1) + fb(m-n+1) \times fb(n) fb(m−n)×fb(n−1)+fb(m−n+1)×fb(n),只要把 f b ( m ) fb(m) fb(m)用 f b ( m − 1 ) , f b ( m − 2 ) … fb(m-1),fb(m-2) \dots fb(m−1),fb(m−2)…表示,最后就能得到这个式子。
于是
G c d ( f b ( n ) , f b ( m ) ) = G c d ( f b ( n ) , f b ( m − n ) × f b ( n − 1 ) + f b ( m − n + 1 ) × f b ( n ) ) Gcd(fb(n),fb(m))=Gcd(fb(n),fb(m-n) \times fb(n-1) + fb(m-n+1) \times fb(n)) Gcd(fb(n),fb(m))=Gcd(fb(n),fb(m−n)×fb(n−1)+fb(m−n+1)×fb(n))
= G c d ( f b ( n ) , f b ( m − n ) × f b ( n − 1 ) ) =Gcd(fb(n),fb(m-n) \times fb(n-1)) =Gcd(fb(n),fb(m−n)×fb(n−1))
又于是,我觉得这个式子没有什么利用价值,于是放弃了。
燃鹅???
f
b
(
n
)
fb(n)
fb(n)和
f
b
(
n
−
1
)
fb(n-1)
fb(n−1)互质,于是这个公式可以再少一项,即:
G c d ( f b ( n ) , f b ( m ) ) = G c d ( f b ( n ) , f b ( m − n ) ) Gcd(fb(n),fb(m))=Gcd(fb(n),fb(m-n)) Gcd(fb(n),fb(m))=Gcd(fb(n),fb(m−n))
最后
G c d ( f b ( n ) , f b ( m ) ) = G c d ( f b ( G c d ( n , m ) ) , 0 ) = f b ( G c d ( n , m ) ) Gcd(fb(n),fb(m))=Gcd(fb(Gcd(n,m)),0)=fb(Gcd(n,m)) Gcd(fb(n),fb(m))=Gcd(fb(Gcd(n,m)),0)=fb(Gcd(n,m))
于是利用结论打个矩阵快速幂这题就结束了。不过想手推结论还是不容易。
#include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long
using namespace std;
const int mod = 1e8;
int a[2][2], b[2][2];
int gcd(int x, int y)
{
while (y){
int rem = x%y;
x = y;
y = rem;
}
return x;
}
void Mul(int a1[2][2], int b1[2][2]) // 史上最丑快速幂
{
int c[2][2];
memset(c, 0, sizeof(c));
for (int i = 0; i < 2; i++)
for (int j = 0; j < 2; j++)
for (int k = 0; k < 2; k++)
(c[i][j] += (ll)a1[i][k]*b1[k][j]%mod) %= mod;
for (int i = 0; i < 2; i++)
for (int j = 0; j < 2; j++)
a1[i][j] = c[i][j];
}
void Ksm(int k)
{
while (k){
if (k&1) Mul(a, b);
Mul(b, b);
k >>= 1;
}
}
int main()
{
int n, m, d;
cin >> n >> m;
d = gcd(n, m);
a[0][0] = a[0][1] = 1;
b[0][0] = b[0][1] = b[1][0] = 1;
Ksm(d-1);
cout << a[0][1]%mod;
return 0;
}