[exgcd]P3986 斐波那契数列 题解
读题,发现 \(k\) 特别大,不是很好办的样子?
然而我们稍微手玩一下就发现题里的常数系数是斐波那契数列,而斐波那契系数的增长是指数级别的。然后你就只需要处理 40 个左右不定方程即可。
这题就变成了一道 exgcd 的板子。
具体操作相当于给你下面这个式子,让你求正整数解的数量。
\[ax + by = c
\]
我记得 exgcd 我以前讲过,因此这里只推一下求出特解后的情况。
\[ax_0 + by_0 = c
\]
当 \(x , y\) 均为正整数
\[x = x_0 + kb
\]
\[y = y_0 - ka
\]
\[\because x_0 + kb = x \geq 1
\]
\[\therefore k \geq \frac{1 - x_0}{b}
\]
\[\because y_0 - ka = y \geq 1
\]
\[\therefore k \leq \frac{y_0 - 1}{a}
\]
然后就能求出 \(k\) 的最大最小值,做差就是数量啦qwq
代码没啥好解释的吧。。。
#include <bits/stdc++.h>
#define int long long
constexpr int N = 47;
constexpr int mod = 1e9 + 7;
using namespace std;
int ans , n , factora[N] = {0 , 1 , 0} , factorb[N] = {0 , 0 , 1};
namespace Exgcd {
inline int gcd(int a , int b) {
return !b ? a : gcd(b , a - a / b * b);
}
inline void exgcd(int a , int b , int &x , int &y) {
if(!b) {
x = 1 , y = 0; return;
}
int x1 , y1;
exgcd(b , a - a / b * b , x1 , y1);
x = y1 , y = x1 - a / b * y1;
}
int solve(int a , int b , int c) {
int d = gcd(a , b) , x0 , y0;
if(c % d) {return 0;}
a /= d , b /= d , c /= d;
exgcd(a , b , x0 , y0);
x0 *= c , y0 *= c;
int k_max = floor((y0 - 1) * 1.0 / a);
int k_min = ceil((1 - x0) * 1.0 / b);
return max(k_max - k_min + 1 , (int)0);
}
}
signed main() {
cin >> n;
for(register int i = 3; i <= 42; ++i) {
factora[i] = factora[i - 1] + factora[i - 2];
factorb[i] = factorb[i - 1] + factorb[i - 2];
}
for(register int i = 1; i <= 42; ++i) {
if(factora[i] + factorb[i] > n) {
break;
}
ans = (ans + Exgcd :: solve(factora[i] , factorb[i] , n)) % mod;
}
cout << ans;
return 0;
}