TIOJ-1494

定義一數列$F$為:
$F_1=1, F_2=2$。
$F_n=F_n-1+F_n-2$。
給定兩正整數$a, b$,求$gcd(F_a, F_b)$

$a, b\le 10^{18}$


$F$其實就是費式數列,只是被位移了一格
先讓他變回正常的費式數列$f(f_1=1,f_2=1)$,此時$F_n=f_{n+1}$。
然後費式數列有個性質:
$$gcd(f_n, f_m)=f_{gcd(n, m)}$$
推導過程需要用蠻多其他定理的,
總之,這樣就等同於求數列某項,直接矩陣快速冪就可以了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
/*
-------------- | /
| | /
| | /
| * |/ | | ------ *
| | | | / \
| | |\ | | | |\ |
\ | | | \ | | | | \ |
\ | | | \ | | \ / \ |
V | | \ \__/| ----- \ |
*/
#include <bits/stdc++.h>
using namespace std;

#define EmiliaMyWife ios::sync_with_stdio(0); cin.tie(NULL);
using ll = int64_t;
const int MOD = 1e9+7;
/*-----------------------------------------------------------------------------------------------------*/

using mat = vector<vector<ll>>;

mat operator*(mat &a, mat &b) {
mat res(2, vector<ll>(2));
for(int i = 0; i < 2; i++)
for(int j = 0; j < 2; j++)
for(int k = 0; k < 2; k++)
res[i][j] = (res[i][j] + a[i][k] * b[k][j]) % MOD;
return res;
}

int get(ll n) {
mat a = {{1, 1}, {1, 0}}, res = {{1, 0}, {0, 1}};
for(; n; n>>=1, a = a * a)
if(n & 1)
res = res * a;
return res[1][0];
}

signed main() {
EmiliaMyWife

ll n, m;
cin >> n >> m;
cout << get(__gcd(n + 1, m + 1)) << '\n';

return 0;
}