×

第四篇:P1306

题解补完计划:第五篇

原题题面

显然,猜想 \((F_n,F_m) = F_{(n,m)}\),接下来是证明。

引理1: \((F_n,F_{n-1}) = 1\)

因为,\(F_n - F_{n-1} = F_{n-2}\),所以 \((F_n, F_{n-1}) = (F_{n-1}, F{n-2})\),根据辗转相除法(相减),可知 \((F_n, F_{n-1}) = (F_1, F_0) = 1\),故,得证。

引理2: \(F_{n+m} = F_{n-1}F_m+F_nF_{m+1}\)

我们固定 \(n\), 尝试对 \(m\) 进行归纳。

  • \(m \le 1\)
    显然成立

  • \(2\le m\)
    我们令对于 \(m, m-1\) 都成立,则有:
    \(\begin{aligned} F_{n+m+1} &= F_{n+m} + F_{n+m-1} \\ &= F_{n-1}F_m+F_nF_{m+1}+F_{n-1}F_{m-1}+F_nF_m \\ &= F_{n-1}(F_m+F_{m-1}) + F_n(F_m+F_{m+1}) \\ &= F_{n-1}F_{m+1} + F_nF_{m+1} \end{aligned}\)

    证毕。

结论 \((F_n,F_m) = F_{(n,m)}\)

由 引理2 可知
\(\begin{aligned} (F_n, F_m) &= (F_n,F_{n+(m-n)}) \\ &= (F_n, F_{n-1}F_{m-n}+F_nF_{m-n+1})\\ &= (F_n, F_{n-1}F_{m-n}) \end{aligned}\)

由 引理1,所以 \((F_n, F_m) = (F_n, F_{m-n})\)。 根据辗转相除法(相减),所以 \((F_n,F_m) = F_{(n,m)}\) 证毕。

好我们在知道 \((F_n, F_m) = F_{(n,m)}\),那是不是就可以只求一个 \(F_{(n,m)}\) 的值,递推做完了,但是 \((n,m)\) 可能到达 \(10^9\) 会超时,我们考虑矩阵优化。

因为 \(F_{n+1} = F_n + F_{n-1}\), 所以我们可以写出下面这个转移矩阵。

\(\begin{bmatrix} 1 & 1 \\ 1 & 0 \end{bmatrix}\)
\(\begin{bmatrix} F_n \\ F_{n-1} \end{bmatrix}\)
$ = \( \)\begin{bmatrix}
F_{n+1} \ F_n
\end{bmatrix}$
我们发现它是对一个重复的矩阵进行转移,所以我们可以用矩阵快速幂优化。

代码:

#include<bits/stdc++.h>
using namespace std;
#define mod 100000000
#define intl long long
#define For(i,a,b) for(intl i=a;i<=b;i++)
#define deo(i,a,b) for(intl i=a;i>=b;i--)
intl read() {
	intl x=0,k=1;char ch=getchar();
	while(!isdigit(ch)) {if(ch == '-') k=-1;ch=getchar();}
	while(isdigit(ch)) {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
	return x*k;
}
void write(intl x) {
	if(x > 9) write(x/10);
	putchar(x%10+'0');
}
struct matx{
	intl a[5][5];
	matx operator * (const matx&b) const {
		matx ans;memset(ans.a,0,sizeof ans.a);
		For(k,1,2) For(i,1,2) For(j,1,2)
		ans.a[i][j] = (ans.a[i][j]+a[i][k]*b.a[k][j])%mod;
		return ans;
	}
}mat;
matx matpow(matx a,intl b){
	matx ans;
	ans.a[1][1]=ans.a[2][1]=1;
	ans.a[1][2]=ans.a[2][2]=0;
	a.a[1][1]=a.a[1][2]=a.a[2][1]=1;
	while(b) {
		if(b&1) ans=a*ans;
		a=a*a;b>>=1;
	}
	return ans;
}
int main(){
	intl n=read(),m=read();
	n=__gcd(n,m);
	if(n <= 2) puts("1");
	else {
		matx ans=matpow(mat,n-2);
		printf("%lld",ans.a[1][1]);
	}	
	return 0;
}
posted @ 2026-10-05 17:22  shiori123  阅读(4)  评论(0)    收藏  举报