前置知识:
矩阵乘法、斐波那契数列的矩阵公式。
题意简要:
用 (F_i) 表示斐波那契数列的第 (i) 项,求:
[gcd(F_n,F_m)
]
我们先考虑 (n > m) .
首先我们考虑 (gcd) 的两个性质,后面要用:
[gcd(a,b) = gcd(b,a-b) = gcd(a-k cdot b)
]
[gcd(a imes b,c) = gcd(a ,c ) imes gcd(b,c)
]
再考虑 (F) 数列的一个性质:
[F_{n+1} - F_n = F_{n-1}
]
下面先求另一个东西:
[gcd(F_n,F_{n+1}) = gcd(F_n,F_{n+1}-F_n) = gcd(F_{n-1},F_n) = cdots = gcd(F_1,F_2)=1
]
得出结论:相邻两个 (F) 的数,其 (gcd) 为 (1).
可以推论:
[F_{n+m}=F_{n+m-1}+F_{n+m-2} = 2 imes F_{n+m-2} + F_{n+m-3} = 3 imes F_{n+m-3} +2 imes F_{n+m-4} = cdots = F_{n+1} cdot F_m + F_n cdot F_{m-1}
]
如果还不懂,可以从上面这个式子进行推论:
[F_{n+m}=F_2 cdot F_{n+m-1}+F_1 cdot F_{n+m-2} = F_3 cdot imes F_{n+m-2} + F_2 cdot F_{n+m-3} = F_4 cdot F_{n+m-3} +F_3 cdot F_{n+m-4} = cdots = F_{n+1} cdot F_m + F_n cdot F_{m-1}
]
(因为每次你会发现,(F) 的系数就是 (F)本身!)
下面可以得出:
[gcd(F_{n+m},F_n) = gcd(F_{n+1} cdot F_m + F_n cdot F_{m-1} ,F_n)
]
下面由于 (gcd) 的性质,约去 (F_n) 一项,再拆开做乘法,可得:
[= gcd(F_{n+1} cdot F_m , F_n) = gcd(F_{n+1},F_n) imes gcd(F_m,F_n)
]
由上面所说结论 (gcd(F_{n+1},F_n=1)) 可推断:
[gcd(F_{n+m},F_n) = gcd(F_m,F_n)
]
由此不断迭代:
[gcd(F_{n+m},F_n) = gcd(F_m,F_n) = gcd(F_{n-m},F_m) = cdots
]
你会发现,这其实就是在实施 辗转相减法 。
那么,辗转相减法的本质就是在求 (gcd) !
所以可以得出:
[gcd(F_n,F_m) = F_{gcd(n,m)}
]
由此,问题简化为:
求 (F) 数列的第 (gcd(n,m)) 项。
显然(如果不会矩阵乘法,或者是矩阵加速等的同学,可以先去学一下),用 矩阵快速幂 可以优雅地解决本题。
时间复杂度为: (O(log n)). 空间复杂度为: (O(1)).(常数级的矩阵大小不计)
(这是因为 (gcd(n,m)) 最大为 (n) 当且仅当 (n=m))
#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll MOD=1e8;
inline ll read(){char ch=getchar();int f=1;while(ch<'0' || ch>'9') {if(ch=='-') f=-f; ch=getchar();}
ll x=0;while(ch>='0' && ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();return x*f;}
ll n,k;
struct martix {
ll a[3][3];
}; //因为函数不能返回数组,只好写结构体
martix ans;
martix a,b;
inline ll gcd(ll n,ll m) {return m?gcd(m,n%m):n;} //gcd迭代
inline martix chengfa(martix x,martix y) {
martix ans;
for(int i=1;i<=2;i++) for(int j=1;j<=2;j++) ans.a[i][j]=0;
for(int i=1;i<=2;i++) for(int j=1;j<=2;j++) for(int k=1;k<=2;k++) {
ans.a[i][j]+=x.a[i][k]*y.a[k][j];
ans.a[i][j]%=MOD;
} return ans;
} //矩阵乘法
inline martix pw(martix a,ll k) {
for(int i=1;i<=2;i++) ans.a[i][i]=1;
while(k>0) {
if(k&1) ans=chengfa(ans,a);
a=chengfa(a,a); k>>=1;
} return ans;
} //矩阵快速幂
int main(){
n=read(),k=read();
if(n<=2) {printf("1");return 0;}
a.a[1][1]=1; a.a[1][2]=1;
b.a[1][1]=0; b.a[1][2]=1; b.a[2][1]=1; b.a[2][2]=1;
martix t=pw(b,gcd(n,k)-2);
ans=chengfa(a,t);
printf("%lld
",ans.a[1][2]); //得出最终结果
return 0;
}