Luogu P3986

题面

我们把题目中给出的数列 f 的各项用 ab 一个个列出来:

a,b,a+b,a+2b,2a+3b,3a+5b,5a+8b

fibi 表示斐波那契数列的第 i 项(下标从 0 开始),容易发现,f(n)=fibn2a+fibn1b

所以问题就转化成了,求下列每个不定方程的正整数解的个数和:

fib0a+fib1b=kfib1a+fib2b=kfib2a+fib3b=k

由于 a,b 都是正整数,当 fibi1+fibi>k 时就不用再往下枚举了。而由于斐波那契数列呈接近指数增长,所以实际我们需要枚举的不定方程个数非常有限。

对于枚举到的不定方程,设 c=fibi1,d=fibi,我们要求出 ac+bd=k 的正整数解个数。

假设我们现在求出了一个最小的 b0,使 b0d<kckb0d,那么,首先 b0 和对应的 a0 是第一组解,然后每隔 lcm(c,d) 个数就又出现一组解,所以总共有 kb0d1lcm(c,d)+1 组解。

b0 我们从 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;
}
posted @   untitled0  阅读(13)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· AI与.NET技术实操系列(六):基于图像分类模型对图像进行分类
点击右上角即可分享
微信分享提示