Luogu P3986
我们把题目中给出的数列 \(f\) 的各项用 \(a\) 和 \(b\) 一个个列出来:
\[a,b,a+b,a+2b,2a+3b,3a+5b,5a+8b\dots
\]
用 \(fib_i\) 表示斐波那契数列的第 \(i\) 项(下标从 \(0\) 开始),容易发现,\(f(n)=fib_{n-2}\,a+fib_{n-1}\,b\)。
所以问题就转化成了,求下列每个不定方程的正整数解的个数和:
\[fib_0\,a+fib_1\,b=k\\fib_1\,a+fib_2\,b=k\\fib_2\,a+fib_3\,b=k\\\dotsb
\]
由于 \(a,b\) 都是正整数,当 \(fib_{i-1}+fib_i>k\) 时就不用再往下枚举了。而由于斐波那契数列呈接近指数增长,所以实际我们需要枚举的不定方程个数非常有限。
对于枚举到的不定方程,设 \(c=fib_{i-1},d=fib_i\),我们要求出 \(ac+bd=k\) 的正整数解个数。
假设我们现在求出了一个最小的 \(b_0\),使 \(b_0d<k\) 且 \(c\mid k-b_0d\),那么,首先 \(b_0\) 和对应的 \(a_0\) 是第一组解,然后每隔 \(\operatorname{lcm}(c,d)\) 个数就又出现一组解,所以总共有 \(\left\lfloor\dfrac{k-b_0d-1}{\operatorname{lcm}(c,d)}\right\rfloor+1\) 组解。
而 \(b_0\) 我们从 \(1\) 开始暴力枚举就可以求出来,因为开始时 \(fib\) 很小,很快就能枚举出答案,而往后 \(fib\) 很大,没枚举几个就超过 \(k\) 了,所以很难卡掉。
代码就非常简单了:
#include<bits/stdc++.h>
#define endl '\n'
using namespace std;
typedef long long ll;
constexpr int p = 1e9 + 7;
ll k, fib[100];
ll gcd(ll a, ll b) {
return b ? gcd(b, a % b) : a;
}
ll lcm(ll a, ll b) {
return a / gcd(a, b) * b;
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> k;
fib[0] = fib[1] = 1;
int e = 1;
for(; fib[e] + fib[e - 1] <= k; ++e)
fib[e + 1] = fib[e] + fib[e - 1];
ll ans = 0;
for(int i = 1; i < e; ++i) {
ll a = fib[i - 1], b = fib[i];
ll x = 1;
while((k - b * x) % a && k > b * x) ++x;
if(k <= b * x) continue;
ans = (ans + (k - b * x - 1) / lcm(a, b) + 1) % p;
}
cout << ans << endl;
return 0;
}

浙公网安备 33010602011771号