[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;
}
posted @ 2025-06-01 00:02  「癔症」  阅读(25)  评论(0)    收藏  举报