洛谷 P1306 斐波那契公约数

题意简述

求斐波那契数列第n项和第m项的最大公约数

题解思路

设斐波那契数列第x项为F[x]
则有结论\(Gcd(F[n], F[m]) = F[Gcd(n, m)]\)

证明:
不妨设n < m
\(F[m]\)
\(= F[m-1] +F[m-2]\)
\(= 2*F[m-2] + F[m-3]\)
\(= 3*F[m-3] + 2*F[m-4]\)
\(= ......\)
\(= F[x+1]*F[m-x] + F[x]*F[m-x-1]\)
\(= F[m-n+1]*F[n] + F[m-n]*F[n-1]\)
所以
\(Gcd(F[n], F[m])\)
\(= Gcd(F[n], F[m-n+1]*F[n] + F[m-n]*F[n-1])\)
\(= Gcd(F[n], F[m-n]*F[n-1])\)
又因为\(Gcd(F[n], F[n-1]) = Gcd(F[n-2], F[n-1]) = ...... = Gcd(F[1], F[2]) = 1\)
所以
\(Gcd(F[n], F[m])\)
\(= Gcd(F[n], F[m-n])\)
同理可得
\(Gcd(F[n], F[m])\)
\(= Gcd(F[n], F[m-n])\)
\(= Gcd(F[n], F[m-2*n])\)
\(= Gcd(F[n], F[m \mod n])\)
然后可以发现,这个过程实际上就是用更相减损术求\(Gcd(m, n)\)
所以\(Gcd(F[n], F[m]) = Gcd(F[Gcd(n, m)], F[Gcd(n, m)]) = F[Gcd(n, m)]\)

最后用矩阵求出斐波那契数列第\(Gcd(m, n)\)项即可

代码

#include <cstdio>
typedef long long ll;
const int mod = 100000000;
int n, m, N, t;
struct Matrix
{
	int a[4][4];
	Matrix& operator =(const Matrix& x)
	{
		for (register int i = 1; i <= N; ++i)
			for (register int j = 1; j <= N; ++j)
				a[i][j] = x.a[i][j];
		return *this;
	}
};
Matrix a, b, c;
int _gcd(int x, int y, int z = 0)
{
	while ((z = x % y)) x = y, y = z;
	return y;
}
Matrix Mul(const Matrix& x, const Matrix& y)
{
	Matrix s;
	for (register int i = 1; i <= N; ++i)
		for (register int j = 1; j <= N; ++j)
			s.a[i][j] = 0;
	for (register int i = 1; i <= N; ++i)
		for (register int j = 1; j <= N; ++j)
			for (register int k = 1; k <= N; ++k)
				s.a[i][j] = (s.a[i][j] + (ll)x.a[i][k] * y.a[k][j] % mod) % mod;
	return s;
}
Matrix _pow(Matrix x, ll y)
{
	Matrix s;
	for (register int i = 1; i <= N; ++i)
		for (register int j = 1; j <= N; ++j)
			s.a[i][j] = (i == j);
	for (; y; y >>= 1, x = Mul(x, x)) if (y & 1) s = Mul(s, x);
	return s;
}
int main()
{
	N = 3;
	scanf("%d%d", &n, &m);
	c.a[1][1] = c.a[1][2] = 1;
	a.a[1][1] = a.a[1][2] = a.a[2][1] = 1;
	n = _gcd(n, m);
	if (n <= 2) {printf("1\n"); return 0; }
	b = Mul(c, _pow(a, n - 2));
	printf("%d\n", b.a[1][1]);
}
posted @ 2018-10-17 20:11  xuyixuan  阅读(148)  评论(0编辑  收藏  举报